View Issue Details

IDProjectCategoryView StatusLast Update
0036976mantisbtsecuritypublic2026-05-09 19:56
Reporterninjasec Assigned Todregad  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionfixed 
Product Version2.28.1 
Target Version2.28.2Fixed in Version2.28.2 
Summary0036976: CVE-2026-34754: Authorization Bypass Allows Uploading Attachments to Private Issues via REST
Description

MantisBT permits an authenticated user to upload an attachment to a private issue they are not authorized to view.

  • The flaw is in the authorization model for existing-issue uploads. The REST endpoint POST /api/rest/issues/{id}/files reaches IssueFileAddCommand.php:134, which delegates permission checking to file_allow_bug_upload():1147.
  • For existing issues, that function authorizes based on project-level upload permission only, not issue-level visibility. As a result, a user who meets upload_bug_file_threshold for the project can upload to a private issue even when view_bug_threshold denies access to that issue.

Affected Components

  • REST route: issues_rest.php:244
  • Command handler: IssueFileAddCommand.php:134
  • Permission check: file_api.php:1147

Root Cause

For existing issues, file_allow_bug_upload() evaluates:

  return access_has_project_level(
    config_get( 'upload_bug_file_threshold' ),
    $t_project_id,
    $p_user_id
  );

This does not enforce private-issue access controls. The authorization decision should be tied to the target issue, not just the project.

Steps To Reproduce

Reproduction

  1. Create or Make an issue private.
  2. Log in as a low-privileged user such as reporter.
  3. Verify direct access to the issue is denied.
  4. Send a REST attachment upload request for that same issue.
  curl -i 'http://127.0.0.1:8082/api/rest/issues/2/files' \
    -H 'Content-Type: application/json' \
    -b 'PHPSESSID=...; MANTIS_secure_session=1; MANTIS_STRING_COOKIE=...' \
    --data '{"files":[{"name":"mantis-rest-upload-issue2.txt","content":"cmVzdC1maWxlLXVwbG9hZC1wb2MtaXNzdWUyCg=="}]}'
Additional Information

Patch

  diff --git a/core/file_api.php b/core/file_api.php
  index 2ec84ef..FIXME 100644
  --- a/core/file_api.php
  +++ b/core/file_api.php
  @@ -1161,7 +1161,11 @@ function file_allow_bug_upload( $p_bug_id = null, $p_user_id = null, $p_project_
        return true;
    }

  - # Check the access level against the config setting
  - return access_has_project_level( config_get( 'upload_bug_file_threshold' ), $t_project_id, $p_user_id );
  + # For existing issues, enforce issue-level access so private / restricted
  + # issues cannot be modified by users who only meet the project threshold.
  + if( $p_bug_id !== null ) {
  +     return access_has_bug_level( config_get( 'upload_bug_file_threshold' ), $p_bug_id, $p_user_id );
  + }
  +
  + return access_has_project_level( config_get( 'upload_bug_file_threshold' ), $t_project_id, $p_user_id );
   }

Clean Final Code

  function file_allow_bug_upload( $p_bug_id = null, $p_user_id = null, $p_project_id = null ) {
    if( null === $p_user_id ) {
        $p_user_id = auth_get_current_user_id();
    }

    # If uploads are disabled just return false
    if( !file_is_uploading_enabled() ) {
        return false;
    }

    if( null === $p_bug_id ) {
        # new bug
        $t_project_id = $p_project_id === null ? helper_get_current_project() : $p_project_id;

        # the user must be the reporter if they're reporting a new bug
        $t_reporter = true;
    } else {
        # existing bug
        $t_project_id = bug_get_field( $p_bug_id, 'project_id' );

        # check if the user is the reporter of the bug
        $t_reporter = bug_is_user_reporter( $p_bug_id, $p_user_id );
    }

    if( $t_reporter && ( ON == config_get( 'allow_reporter_upload' ) ) ) {
        return true;
    }

    if( $p_bug_id !== null ) {
        return access_has_bug_level(
            config_get( 'upload_bug_file_threshold' ),
            $p_bug_id,
            $p_user_id
        );
    }

    return access_has_project_level(
        config_get( 'upload_bug_file_threshold' ),
        $t_project_id,
        $p_user_id
    );
  }

In short:

  • new issue upload:
    access_has_project_level(upload_bug_file_threshold, project_id, user_id)
    uploading to a new issue in a project still works if the user has project upload permission
  • existing issue upload:
    access_has_bug_level(upload_bug_file_threshold, bug_id, user_id)
    uploading to an existing private issue now correctly requires issue-level access and is denied
TagsNo tags attached.
Attached Files
image.png (405,399 bytes)
image-2.png (216,372 bytes)   
image-2.png (216,372 bytes)   

Activities

dregad

dregad

2026-03-30 13:27

developer   ~0070918

Vulnerability is confirmed. Thanks for the detailed analysis and proposed patch.

Advisory created https://github.com/mantisbt/mantisbt/security/advisories/GHSA-h4x5-gvx6-3rwc and CVE request sent.

dregad

dregad

2026-03-30 13:37

developer   ~0070919

Last edited: 2026-03-30 13:42

Proposed patch is available at https://github.com/mantisbt/mantisbt-ghsa-fvjf-68wh-rwp2/pull/1/commits/8f163016990cbcd13294e6a95a3de6ec66ffb912 (note that the private repo is linked to another advisory; I did that to minimize effort as I'm working on several security issues from the same researcher in parallel).

dregad

dregad

2026-03-31 03:04

developer   ~0070921

CVE-2026-34754 assigned

Related Changesets

MantisBT: master-2.28 b262b4d2

2026-03-30 13:32

dregad


Details Diff
Prevent unauthorized attachment upload via REST

file_allow_project_upload() has been modified to check access for
upload_bug_file_threshold against
- project for new issues
- bug for existing issues

Fixes 0036976, GHSA-h4x5-gvx6-3rwc
Affected Issues
0036976
mod - core/file_api.php Diff File