View Issue Details

IDProjectCategoryView StatusLast Update
0037093mantisbtsecuritypublic2026-05-10 07:58
ReporterTristanInSec Assigned Todregad  
PriorityhighSeveritymajorReproducibilityalways
Status closedResolutionduplicate 
Summary0037093: Authorization Bypass in Bugnote Editing via Issue Update API
Description

The mc_issue_update() function in MantisBT allows users with UPDATER (level 40) access to edit, change view state, and modify time tracking on bugnotes belonging to other users — bypassing the DEVELOPER (level 55) threshold required by the dedicated mc_issue_note_update() function.

Vulnerability Details

  • CWE: CWE-863 (Incorrect Authorization)
  • CVSS 3.1: 5.4 (Medium) — AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
  • Affected Version: MantisBT 2.29.0-dev (and likely all prior versions with SOAP/REST API)
  • Auth Required: UPDATER access level (level 40) to the project

Root Cause

mc_issue_update() in api/soap/mc_issue_api.php checks only update_bug_threshold (UPDATER, level 40) at line 1012 before processing note modifications at lines 1180-1208:

// Line 1012 — only gate for the entire function
if( !access_has_bug_level( config_get( 'update_bug_threshold' ), $p_issue_id, $t_user_id ) ) {
    return mci_fault_access_denied( $t_user_id, 'Not enough rights to update issues' );
}

// Lines 1189-1196 — NO per-note auth check
if( isset( $t_note['text']) && $t_bugnote->note !== $t_note['text'] ) {
    bugnote_set_text( $t_bugnote_id, $t_note['text'] );     // Direct DB write
}
if( $t_bugnote->view_state != $t_view_state_id ) {
    bugnote_set_view_state( $t_bugnote_id, $t_view_state_id == VS_PRIVATE );  // Direct DB write
}

The functions bugnote_set_text(), bugnote_set_view_state(), and bugnote_set_time_tracking() are raw database operations with zero authorization checks.

In contrast, the dedicated mc_issue_note_update() (line 1461) properly enforces:

  • bugnote_user_edit_threshold for note owners (line 1497-1498)
  • update_bugnote_threshold for non-owners (line 1504-1506)
    Both default to DEVELOPER (level 55).

Default Access Levels

Config Default Level
update_bug_threshold UPDATER 40
update_bugnote_threshold DEVELOPER 55
bugnote_user_edit_threshold DEVELOPER 55

Impact

  1. UPDATER can edit notes by DEVELOPER/MANAGER/ADMIN — bypassing the DEVELOPER threshold
  2. UPDATER can change private notes to public — exposing confidential internal discussion
  3. UPDATER can change public notes to private — hiding information from reporters/viewers
Steps To Reproduce

Proof of Concept

# As UPDATER user, modify note #42 (written by admin) on issue #5
curl -X PATCH "http://mantis.local/api/rest/issues/5" \
  -H "Authorization: UPDATER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "notes": [{
      "id": 42,
      "text": "MODIFIED BY UPDATER",
      "view_state": {"id": 10, "name": "public"}
    }]
  }'

This succeeds via REST API but the same user would be denied via the dedicated note update endpoint.

Additional Information

Fix

Add per-note authorization checks in the mc_issue_update() note modification loop (around line 1185):

if( array_key_exists( $t_bugnote_id, $t_bugnotes_by_id ) ) {
    $t_bugnote = $t_bugnotes_by_id[$t_bugnote_id];

    // ADD: Check note-level edit permission
    $t_user_owns_note = ($t_bugnote->reporter_id == $t_user_id);
    if( $t_user_owns_note ) {
        $t_edit_threshold = config_get('bugnote_user_edit_threshold', null, $t_user_id, $t_project_id);
        if( !access_has_bugnote_level( $t_edit_threshold, $t_bugnote_id, $t_user_id ) ) {
            return mci_fault_access_denied( $t_user_id );
        }
    } else {
        $t_edit_threshold = config_get('update_bugnote_threshold', null, $t_user_id, $t_project_id);
        if( !access_has_bugnote_level( $t_edit_threshold, $t_bugnote_id, $t_user_id ) ) {
            return mci_fault_access_denied( $t_user_id );
        }
    }
    // ... existing code ...
}
TagsNo tags attached.
Attached Files
vuln-2-bugnote-edit-auth-bypass.md (3,909 bytes)   
# Authorization Bypass in Bugnote Editing via Issue Update API

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

## Summary

The `mc_issue_update()` function in MantisBT allows users with UPDATER (level 40) access to edit, change view state, and modify time tracking on bugnotes belonging to other users — bypassing the DEVELOPER (level 55) threshold required by the dedicated `mc_issue_note_update()` function.

## Vulnerability Details

- **CWE**: CWE-863 (Incorrect Authorization)
- **CVSS 3.1**: 5.4 (Medium) — `AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L`
- **Affected Version**: MantisBT 2.29.0-dev (and likely all prior versions with SOAP/REST API)
- **Auth Required**: UPDATER access level (level 40) to the project

## Root Cause

`mc_issue_update()` in `api/soap/mc_issue_api.php` checks only `update_bug_threshold` (UPDATER, level 40) at line 1012 before processing note modifications at lines 1180-1208:

```php
// Line 1012 — only gate for the entire function
if( !access_has_bug_level( config_get( 'update_bug_threshold' ), $p_issue_id, $t_user_id ) ) {
    return mci_fault_access_denied( $t_user_id, 'Not enough rights to update issues' );
}

// Lines 1189-1196 — NO per-note auth check
if( isset( $t_note['text']) && $t_bugnote->note !== $t_note['text'] ) {
    bugnote_set_text( $t_bugnote_id, $t_note['text'] );     // Direct DB write
}
if( $t_bugnote->view_state != $t_view_state_id ) {
    bugnote_set_view_state( $t_bugnote_id, $t_view_state_id == VS_PRIVATE );  // Direct DB write
}
```

The functions `bugnote_set_text()`, `bugnote_set_view_state()`, and `bugnote_set_time_tracking()` are raw database operations with **zero authorization checks**.

In contrast, the dedicated `mc_issue_note_update()` (line 1461) properly enforces:
- `bugnote_user_edit_threshold` for note owners (line 1497-1498)
- `update_bugnote_threshold` for non-owners (line 1504-1506)
Both default to DEVELOPER (level 55).

## Default Access Levels

| Config | Default | Level |
|--------|---------|-------|
| `update_bug_threshold` | UPDATER | 40 |
| `update_bugnote_threshold` | DEVELOPER | 55 |
| `bugnote_user_edit_threshold` | DEVELOPER | 55 |

## Impact

1. **UPDATER can edit notes by DEVELOPER/MANAGER/ADMIN** — bypassing the DEVELOPER threshold
2. **UPDATER can change private notes to public** — exposing confidential internal discussion
3. **UPDATER can change public notes to private** — hiding information from reporters/viewers

## Proof of Concept

```bash
# As UPDATER user, modify note #42 (written by admin) on issue #5
curl -X PATCH "http://mantis.local/api/rest/issues/5" \
  -H "Authorization: UPDATER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "notes": [{
      "id": 42,
      "text": "MODIFIED BY UPDATER",
      "view_state": {"id": 10, "name": "public"}
    }]
  }'
```

This succeeds via REST API but the same user would be denied via the dedicated note update endpoint.

## Fix

Add per-note authorization checks in the `mc_issue_update()` note modification loop (around line 1185):

```php
if( array_key_exists( $t_bugnote_id, $t_bugnotes_by_id ) ) {
    $t_bugnote = $t_bugnotes_by_id[$t_bugnote_id];

    // ADD: Check note-level edit permission
    $t_user_owns_note = ($t_bugnote->reporter_id == $t_user_id);
    if( $t_user_owns_note ) {
        $t_edit_threshold = config_get('bugnote_user_edit_threshold', null, $t_user_id, $t_project_id);
        if( !access_has_bugnote_level( $t_edit_threshold, $t_bugnote_id, $t_user_id ) ) {
            return mci_fault_access_denied( $t_user_id );
        }
    } else {
        $t_edit_threshold = config_get('update_bugnote_threshold', null, $t_user_id, $t_project_id);
        if( !access_has_bugnote_level( $t_edit_threshold, $t_bugnote_id, $t_user_id ) ) {
            return mci_fault_access_denied( $t_user_id );
        }
    }
    // ... existing code ...
}
```

Relationships

duplicate of 0037089 closeddregad CVE-2026-42070: REST/SOAP mc_issue_update Embedded Note Update Bypasses Note-Level Authorization 

Activities

dregad

dregad

2026-04-19 19:10

developer   ~0071038

Many thanks for the detailed and well-written report.

This vulnerability has already been identified by another researcher, so I'm closing this as duplicate of 0037089, but I will nevertheless credit you for the finding (CVE has not yet been assigned). As mentioned in my earlier email, please let me know your GitHub Id.

dregad

dregad

2026-04-24 13:03

developer   ~0071045

  1. UPDATER can change private notes to public — exposing confidential internal discussion

This case is only reproducible when the UPDATER user also has private_bugnote_threshold (which is not the case by default).

mc_issue_update() calls bugnote_get_all_visible_bugnotes(), which only returns bugnotes the UPDATER user has access to, excluding other user's private notes.

dregad

dregad

2026-05-02 05:38

developer   ~0071057

@TristanInSec I have a patch ready for review to fix this vulnerability, I have sent you an invite to a private repository so you can have a look and provide feedback.