MantisBT has a 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 download attachments on private bugnotes they should not be able to access, via the REST API endpoint GET /api/rest/issues/{id}/files and SOAP API mc_issue_attachment_get endpoint.
### 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
### Patches - 029d9d203d9e4ae96b3e59d552fa7395cc1e5071
Workarounds
None
Credits
Thanks to the following security researchers for independently discovering and responsibly reporting the issue. - Vishal Shukla - Tristan Madani (@TristanInSec) from Talence Security - Tang Cheuk Hei (@siunam321)
This advisory's contents was largely copied from Tristan's well-written report.
Affected products
1Patches
1029d9d203d9eMerge branch 'sec-36985-private-attachment-leak' into release/2.28.2
3 files changed · +15 −21
api/soap/mc_file_api.php+5 −17 modified@@ -23,22 +23,6 @@ * @link http://www.mantisbt.org */ -/** - * Check if the current user can download attachments for the specified bug. - * @param integer $p_bug_id A bug identifier. - * @param integer $p_user_id A user identifier. - * @return boolean - */ -function mci_file_can_download_bug_attachments( $p_bug_id, $p_user_id ) { - $t_can_download = access_has_bug_level( config_get( 'download_attachments_threshold' ), $p_bug_id ); - if( $t_can_download ) { - return true; - } - - $t_reported_by_me = bug_is_user_reporter( $p_bug_id, $p_user_id ); - return( $t_reported_by_me && config_get( 'allow_download_own_attachments' ) ); -} - /** * Read a local file and return its content. * @param string $p_diskfile Name of file on disk. @@ -222,6 +206,8 @@ function mci_file_get( $p_file_id, $p_type, $p_user_id ) { $t_project_id = $t_row['project_id']; } else if( $p_type == 'bug' ) { $t_bug_id = $t_row['bug_id']; + $t_bugnote_id = $t_row['bugnote_id']; + $t_owner_id = $t_row['user_id']; $t_project_id = bug_get_field( $t_bug_id, 'project_id' ); } @@ -231,7 +217,9 @@ function mci_file_get( $p_file_id, $p_type, $p_user_id ) { # Check access rights switch( $p_type ) { case 'bug': - if( !mci_file_can_download_bug_attachments( $t_bug_id, $p_user_id ) ) { + if( !file_can_download_bug_attachments( $t_bug_id, $t_owner_id ) + || !file_can_download_bugnote_attachments( $t_bugnote_id, $t_owner_id, $t_bug_id ) + ) { return mci_fault_access_denied( $p_user_id ); } break;
core/file_api.php+9 −3 modified@@ -309,7 +309,7 @@ function file_can_view_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = $t_bug_id = (int)$p_bug_id; } - return file_can_view_or_download( 'view', $t_bug_id, $p_uploader_user_id ); + return file_can_view_or_download( 'view', $t_bug_id, $p_uploader_user_id, $p_bugnote_id ); } /** @@ -330,15 +330,21 @@ function file_can_download_bug_attachments( $p_bug_id, $p_uploader_user_id = nul * * @param int $p_bugnote_id A bugnote identifier. * @param int $p_uploader_user_id The user who uploaded the attachment. + * @param int $p_bug_id The bug id; if null (default), will be retrieved + * from bugnote record. * * @return bool * @throws ClientException */ -function file_can_download_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = null ) { +function file_can_download_bugnote_attachments( $p_bugnote_id, $p_uploader_user_id = null, $p_bug_id = null ) { if( $p_bugnote_id == 0 ) { return true; } - $t_bug_id = bugnote_get_field( $p_bugnote_id, 'bug_id' ); + 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( 'download', $t_bug_id, $p_uploader_user_id, $p_bugnote_id ); }
file_download.php+1 −1 modified@@ -123,7 +123,7 @@ switch( $f_type ) { case 'bug': if( !file_can_download_bug_attachments( $v_bug_id, $v_user_id ) - || !file_can_download_bugnote_attachments( $v_bugnote_id, $v_user_id ) + || !file_can_download_bugnote_attachments( $v_bugnote_id, $v_user_id, $v_bug_id ) ) { access_denied(); }
Vulnerability mechanics
AI mechanics synthesis has not run for this CVE yet.
References
7- github.com/advisories/GHSA-pw5x-2mf9-3xc8ghsaADVISORY
- github.com/advisories/GHSA-xjmx-cprh-646rghsa
- github.com/mantisbt/mantisbt/commit/029d9d203d9e4ae96b3e59d552fa7395cc1e5071ghsa
- github.com/mantisbt/mantisbt/security/advisories/GHSA-pw5x-2mf9-3xc8ghsa
- mantisbt.org/bugs/view.phpghsa
- mantisbt.org/bugs/view.phpghsa
- mantisbt.org/bugs/view.phpghsa
News mentions
0No linked articles in our index yet.