Skip to content

fix(security): restrict desktop bridge to same-origin browsers - #740

Open
imMamdouhaboammar wants to merge 1 commit into
lsdefine:mainfrom
imMamdouhaboammar:fix/desktop-bridge-origin-guard-upstream
Open

fix(security): restrict desktop bridge to same-origin browsers#740
imMamdouhaboammar wants to merge 1 commit into
lsdefine:mainfrom
imMamdouhaboammar:fix/desktop-bridge-origin-guard-upstream

Conversation

@imMamdouhaboammar

Copy link
Copy Markdown

Summary

The desktop bridge currently emits wildcard CORS responses and accepts browser requests without a trustworthy Origin boundary. Because browsers can reach loopback HTTP services, an unrelated page can attempt to invoke sensitive bridge endpoints such as agent prompt submission and configuration writes.

This patch restricts browser access while preserving the bundled desktop UI and native/local callers.

Root cause

cors_middleware() accepted every Origin and returned Access-Control-Allow-Origin: * for preflight and normal responses. json_ok() independently added the same wildcard header.

A simple Origin == Host comparison is also insufficient on a loopback service because both headers can contain the same attacker-controlled hostname in a DNS-rebinding scenario.

Changes

  • Reject cross-origin browser requests before route dispatch
  • When the bridge is bound to loopback, require both the Origin hostname and request Host hostname to be known loopback names: 127.0.0.1, localhost, or ::1
  • For intentional non-loopback binds, require the validated Origin authority to match request.host
  • Accept only serialized HTTP(S) Origin values with a valid port and no userinfo, path, query, or fragment
  • Reject opaque values such as Origin: null
  • Reflect only an accepted Origin instead of *, with Vary: Origin
  • Remove unconditional CORS headers from json_ok()
  • Preserve requests without Origin for native/local callers
  • Include PATCH in the preflight method list to match the existing PATCH route
  • Make the regression test hermetic by importing the bridge against an isolated temporary GA_ROOT, preventing import-time upload cleanup from touching developer data

The Tauri shell already navigates the main webview to http://127.0.0.1:14168/, so the bundled UI remains allowed.

Regression coverage

The test suite covers:

  1. Isolated temporary GA root during module import
  2. Cross-origin preflight rejection
  3. Cross-origin POST rejection
  4. DNS-rebinding-style matching attacker Host/Origin rejection on loopback
  5. Rejection of malformed serialized Origins: path, query, userinfo, invalid port, and fragment
  6. Origin: null rejection
  7. Valid same-origin browser access with reflected ACAO
  8. No-Origin native/local access without ACAO

Verification

  • Initial RED confirmed current main returned 204 plus wildcard ACAO for a cross-origin preflight
  • A later DNS-rebinding regression was added and independently observed failing before the loopback anchor was added
  • Malformed-Origin cases were added after review and independently observed failing before strict parsing was added
  • python -m py_compile frontends/desktop_bridge.py tests/test_desktop_bridge_origin.py passed during the implementation gate
  • Full regression tests and git diff --check passed before each production patch commit
  • Final persisted-state GitHub Actions run 31160123977 passed the test job while every self-patching step was skipped, proving the committed code itself is green
  • Final contribution branch is exactly one commit ahead of current main and changes only two files

No new runtime dependency is added. aiohttp is already a core dependency.

Residual boundary

This is a browser-origin fix, not authentication for trusted local processes. Requests without Origin remain allowed for native/local clients by design. A per-launch token would be a separate defense-in-depth change.

The connected GitHub integration has write access to this fork, but upstream write operations return 403 Resource not accessible by integration, so I cannot open the cross-fork PR to lsdefine/GenericAgent directly from this session.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant