View Issue Details

IDProjectCategoryView StatusLast Update
0037092mantisbtsecuritypublic2026-05-10 07:57
ReporterTristanInSec Assigned Todregad  
PriorityhighSeveritymajorReproducibilityhave not tried
Status closedResolutionduplicate 
Summary0037092: Private Bugnote Attachment Content Leak via REST API
Description

A missing authorization check in MantisBT's file visibility function allows any authenticated user (REPORTER+) to view attachments on private bugnotes they should not be able to access, via the REST API endpoint GET /api/rest/issues/{id}/files.

Vulnerability Details

  • CWE: CWE-862 (Missing Authorization)
  • CVSS 3.1: 6.5 (Medium) — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
  • Affected Version: MantisBT 2.29.0-dev (and likely all prior versions with REST API)
  • Auth Required: Any authenticated user with view_attachments_threshold (default: VIEWER, access level 10)

Root Cause

file_can_view_bugnote_attachments() in core/file_api.php:298-310 does NOT pass $p_bugnote_id to file_can_view_or_download():

function file_can_view_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = null, $p_bug_id = null ) {
    if( $p_bugnote_id == 0 ) { return true; }
    // ...
    return file_can_view_or_download( 'view', $t_bug_id, $p_uploader_user_id );
    //                                                     ^^^^ no bugnote_id
}

Compare with file_can_download_bugnote_attachments() at line 334-340 which correctly passes it:

function file_can_download_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = null ) {
    // ...
    return file_can_view_or_download( 'download', $t_bug_id, $p_uploader_user_id, $p_bugnote_id );
    //                                                                             ^^^^^^^^^^^^
}

When $p_bugnote_id is passed, file_can_view_or_download() (line 260-264) uses access_has_bugnote_level() which checks the bugnote's view_state against private_bugnote_threshold. Without it, only a bug-level access check is performed, ignoring note privacy.

Data Flow

  1. GET /api/rest/issues/{id}/files -> IssueFileGetCommand::process() (core/commands/IssueFileGetCommand.php:65)
  2. -> file_get_visible_attachments($this->issue_id) (line 78)
  3. -> file_can_view_bugnote_attachments() called at file_api.php:501 — does NOT check bugnote view_state
  4. -> file_get_content($t_attachment['id']) (line 85) returns full file content
  5. Response includes metadata AND base64-encoded content for ALL attachments, including those on private bugnotes

Impact

  • REPORTER (access level 25) can view file attachments that were uploaded to private bugnotes by DEVELOPER/MANAGER/ADMIN users
  • Private bugnotes are intended for internal developer discussion; their attachments (logs, screenshots, patches) should be equally protected
  • The web UI is NOT affected — it filters through bugnote_get_all_visible_bugnotes() first
Steps To Reproduce
#!/bin/bash
# PoC: Private bugnote attachment leak via REST API
#
# Prerequisites:
# 1. MantisBT instance at $MANTIS_URL
# 2. A bug with a private bugnote that has an attachment
# 3. API token for a REPORTER user (who should NOT see private bugnote attachments)

MANTIS_URL="http://localhost:8989"
API_TOKEN="YOUR_REPORTER_API_TOKEN"
ISSUE_ID=1

# Step 1: Create a private bugnote with attachment (as DEVELOPER/ADMIN)
# This would normally be done via the web UI:
# - Go to issue #1
# - Add a bugnote with "Private" view state
# - Attach a file to the bugnote

# Step 2: As REPORTER, fetch all attachments for the issue
curl -s -H "Authorization: ${API_TOKEN}" \
     "${MANTIS_URL}/api/rest/issues/${ISSUE_ID}/files" | python3 -m json.tool

# Expected: Should NOT include attachments from private bugnotes
# Actual: Returns ALL attachments including those on private bugnotes,
#         with full base64-encoded content
Additional Information

Fix

In file_can_view_bugnote_attachments(), pass $p_bugnote_id to file_can_view_or_download():

function file_can_view_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = null, $p_bug_id = null ) {
    if( $p_bugnote_id == 0 ) { return true; }
    if( $p_bug_id === null ) {
        $t_bug_id = bugnote_get_field( $p_bugnote_id, 'bug_id' );
    } else {
        $t_bug_id = (int)$p_bug_id;
    }
    return file_can_view_or_download( 'view', $t_bug_id, $p_uploader_user_id, $p_bugnote_id );
    //                                                                         ^^^^^^^^^^^^
}
TagsNo tags attached.
Attached Files
vuln-1-private-bugnote-attachment-leak.md (4,375 bytes)   
# Private Bugnote Attachment Content Leak via REST API

**Validation: Code trace** (TODO — manual review required, lint-added 2026-04-16)

## Summary

A missing authorization check in MantisBT's file visibility function allows any authenticated user (REPORTER+) to view attachments on **private bugnotes** they should not be able to access, via the REST API endpoint `GET /api/rest/issues/{id}/files`.

## Vulnerability Details

- **CWE**: CWE-862 (Missing Authorization)
- **CVSS 3.1**: 6.5 (Medium) — `AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N`
- **Affected Version**: MantisBT 2.29.0-dev (and likely all prior versions with REST API)
- **Auth Required**: Any authenticated user with `view_attachments_threshold` (default: VIEWER, access level 10)

## Root Cause

`file_can_view_bugnote_attachments()` in `core/file_api.php:298-310` does NOT pass `$p_bugnote_id` to `file_can_view_or_download()`:

```php
function file_can_view_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = null, $p_bug_id = null ) {
    if( $p_bugnote_id == 0 ) { return true; }
    // ...
    return file_can_view_or_download( 'view', $t_bug_id, $p_uploader_user_id );
    //                                                     ^^^^ no bugnote_id
}
```

Compare with `file_can_download_bugnote_attachments()` at line 334-340 which **correctly** passes it:

```php
function file_can_download_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = null ) {
    // ...
    return file_can_view_or_download( 'download', $t_bug_id, $p_uploader_user_id, $p_bugnote_id );
    //                                                                             ^^^^^^^^^^^^
}
```

When `$p_bugnote_id` is passed, `file_can_view_or_download()` (line 260-264) uses `access_has_bugnote_level()` which checks the bugnote's `view_state` against `private_bugnote_threshold`. Without it, only a bug-level access check is performed, ignoring note privacy.

## Data Flow

1. `GET /api/rest/issues/{id}/files` -> `IssueFileGetCommand::process()` (core/commands/IssueFileGetCommand.php:65)
2. -> `file_get_visible_attachments($this->issue_id)` (line 78)
3. -> `file_can_view_bugnote_attachments()` called at file_api.php:501 — **does NOT check bugnote view_state**
4. -> `file_get_content($t_attachment['id'])` (line 85) returns full file content
5. Response includes metadata AND base64-encoded content for ALL attachments, including those on private bugnotes

## Impact

- **REPORTER** (access level 25) can view file attachments that were uploaded to **private bugnotes** by DEVELOPER/MANAGER/ADMIN users
- Private bugnotes are intended for internal developer discussion; their attachments (logs, screenshots, patches) should be equally protected
- The web UI is NOT affected — it filters through `bugnote_get_all_visible_bugnotes()` first

## Proof of Concept

```bash
#!/bin/bash
# PoC: Private bugnote attachment leak via REST API
#
# Prerequisites:
# 1. MantisBT instance at $MANTIS_URL
# 2. A bug with a private bugnote that has an attachment
# 3. API token for a REPORTER user (who should NOT see private bugnote attachments)

MANTIS_URL="http://localhost:8989"
API_TOKEN="YOUR_REPORTER_API_TOKEN"
ISSUE_ID=1

# Step 1: Create a private bugnote with attachment (as DEVELOPER/ADMIN)
# This would normally be done via the web UI:
# - Go to issue #1
# - Add a bugnote with "Private" view state
# - Attach a file to the bugnote

# Step 2: As REPORTER, fetch all attachments for the issue
curl -s -H "Authorization: ${API_TOKEN}" \
     "${MANTIS_URL}/api/rest/issues/${ISSUE_ID}/files" | python3 -m json.tool

# Expected: Should NOT include attachments from private bugnotes
# Actual: Returns ALL attachments including those on private bugnotes,
#         with full base64-encoded content
```

## Fix

In `file_can_view_bugnote_attachments()`, pass `$p_bugnote_id` to `file_can_view_or_download()`:

```php
function file_can_view_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = null, $p_bug_id = null ) {
    if( $p_bugnote_id == 0 ) { return true; }
    if( $p_bug_id === null ) {
        $t_bug_id = bugnote_get_field( $p_bugnote_id, 'bug_id' );
    } else {
        $t_bug_id = (int)$p_bug_id;
    }
    return file_can_view_or_download( 'view', $t_bug_id, $p_uploader_user_id, $p_bugnote_id );
    //                                                                         ^^^^^^^^^^^^
}
```

Relationships

duplicate of 0036985 closeddregad CVE-2026-42071: REST Issue File Listing Leaks Attachments From Hidden Private Bugnotes 

Activities

dregad

dregad

2026-04-19 19:50

developer   ~0071040

Many thanks for the detailed and well-written report.

This vulnerability has already been identified by another researcher, so I'm closing this Issue as duplicate of 0036985. CVE has not yet been assigned. You will be co-credited for the finding.

dregad

dregad

2026-05-02 09:28

developer   ~0071059

@TristanInSec I have a patch ready for review to fix this vulnerability, please accept the invitation to the private repository I sent you this morning to access it, feedback welcome.