[UI] Fix path traversal vulnerability in bridge.py

← All Specs

Goal

Fix critical path traversal vulnerability in bridge.py that allows attackers to write to arbitrary filesystem locations outside the intended BASE directory. The current validation checks if the path string starts with BASE before resolving relative paths, enabling bypass via ../../ sequences.

Root Cause

Lines 32-33 in bridge.py:

fp=os.path.join(BASE,body["path"].lstrip("/"))
if not fp.startswith(BASE):self.send_response(403);self.end_headers();return

Attack vector:

  • Attacker sends path: ../../etc/passwd
  • os.path.join("/home/ubuntu/scidex", "../../etc/passwd")"/home/ubuntu/scidex/../../etc/passwd"
  • String starts with BASE ("/home/ubuntu/scidex") ✓ passes check
  • But resolves to /home/etc/passwd when accessed
  • Evidence: Service crashed on 2026-04-02 00:39:38 with:

    PermissionError: [Errno 13] Permission denied: '/home/ubuntu/scidex/../../etc'

    Acceptance Criteria

    ☑ Spec file created
    ☑ Path validation uses realpath() to resolve symlinks and relative paths before check
    ☑ Security test script created with common bypass techniques
    ☑ All bypass attempts correctly blocked (403 response)
    ☑ Legitimate paths within BASE still work
    ☑ Bridge service restarted and operational
    ☑ No permission errors in service logs
    ☑ Commit and push fix

    Approach

  • Read current bridge.py implementation
  • Replace unsafe validation with secure pattern:

  • fp = os.path.realpath(os.path.join(BASE, body["path"].lstrip("/")))
       if not fp.startswith(os.path.realpath(BASE)):
           self.send_response(403)
           self.end_headers()
           return

  • Create security_test_bridge.py to test:
  • - ../../etc/passwd → 403
    - ../../../etc/hosts → 403
    - Symlink attacks
    - Legitimate paths → 200
  • Validate syntax with py_compile
  • Restart bridge service
  • Run security tests
  • Monitor service logs for errors
  • Work Log

    2026-04-02 03:48 PT — Slot 7

    • Created task after discovering path traversal vulnerability
    • Service crashed attempting to write to /etc via ../ bypass
    • Root cause: validation happens before path resolution
    • Creating spec and implementing fix

    2026-04-02 03:53 PT — Slot 7

    • Implemented security fix in bridge.py:
    - Changed line 32: Added os.path.realpath() to resolve paths before validation
    - Changed line 33: Added os.path.realpath(BASE)+os.sep to prevent edge case bypasses
    • Created security_test_bridge.py with 13 test cases (8 attacks + 5 legitimate paths)
    • Ran security tests: ALL 13 TESTS PASSED
    - All path traversal attempts correctly blocked (../../etc/passwd, symlinks, etc.)
    - All legitimate paths correctly allowed (site/, logs/, api.py, etc.)
    • Validated Python syntax: OK
    • Restarted scidex-bridge service: active and running
    • Verified bridge responds: /health endpoint returns 200 OK
    • Bridge service now secure against path traversal attacks
    • Result: COMPLETE — security vulnerability fixed and verified

    2026-04-20 18:45 PT — Slot 42

    • Rechecked current main state after audit reopened the task: the bridge service now lives at scripts/bridge.py, and prior commits for this task are not ancestors of origin/main.
    • Hardened upload path validation by replacing string-prefix containment with Path.resolve().relative_to(), which blocks sibling-prefix and symlink escapes after resolution.
    • Moved the no-token startup exit under __main__ so the path validator can be imported by tests without starting the bridge service.
    • Added tests/test_bridge_path_validation.py covering legitimate in-base paths, parent traversal, absolute paths, and symlink escape into a sibling directory.
    • Added a root bridge.py compatibility entrypoint because the deployed scidex-bridge.service still invokes /home/ubuntu/scidex/bridge.py while the maintained implementation lives in scripts/bridge.py.

    Already Resolved — 2026-04-24 15:20:00Z

    Evidence run on 2026-04-24:

    • git show origin/main:scripts/bridge.py confirms resolve_upload_path uses Path.resolve().relative_to() — the secure pattern.
    • git show origin/main:bridge.py confirms compatibility entrypoint delegates to scripts/bridge.py.
    • git show origin/main:tests/test_bridge_path_validation.py confirms all 5 test cases exist.
    • python3 -m pytest tests/test_bridge_path_validation.py -v5 passed (parent traversal blocked, absolute paths blocked, symlink escape blocked, legitimate paths allowed, no-shell subprocess verified).
    Commit that landed the fix: 698ed86b2 (Squash merge: orchestra/task/126b98c0-senate-db-health-check-10-abandons)

    Summary: Path traversal vulnerability fully fixed. resolve_upload_path() uses pathlib.Path.resolve().relative_to() to resolve all symlinks and relative sequences before validation, blocking all documented bypass techniques. All 5 security tests pass on main.

    Tasks using this spec (1)
    [UI] Fix path traversal vulnerability in bridge.py
    UI done P95
    File: 58e83560_332_spec.md
    Modified: 2026-04-25 23:40
    Size: 5.0 KB