Skip to content

fix(extension): withhold auth token from content-script getPort callers#1822

Open
Mike-E-Log wants to merge 1 commit into
garrytan:mainfrom
Mike-E-Log:fix-extension-getport-token-guard
Open

fix(extension): withhold auth token from content-script getPort callers#1822
Mike-E-Log wants to merge 1 commit into
garrytan:mainfrom
Mike-E-Log:fix-extension-getport-token-guard

Conversation

@Mike-E-Log
Copy link
Copy Markdown

Re-opens #1788, which was auto-closed when my fork was briefly detached from the network (my mistake, not a maintainer action). Identical guard, rebased on current main — which is still vulnerable as of this PR.

Summary

Bug: A content script can ask extension/background.js for the localhost auth token and get it.

Root cause: The chrome.runtime.onMessage listener has two paths that hand back the token. getToken already guards it (if (sender.tab)token: null), so content scripts get nothing. getPort, a few lines above, returns { port, connected, token: authToken } to every caller. The top-level sender.id !== chrome.runtime.id check only rejects other extensions, not this extension's own content scripts, so a content script that sends getPort receives the same token getToken deliberately withholds.

Fix

Apply the same sender.tab guard to getPort, matching the adjacent getToken precedent in extension/background.js. port and connected stay available to any extension context; token is null for content-script callers.

Test plan

  • 1 file changed, +7/-1.
  • Sidepanel and popup callers (no sender.tab) are unchanged; they still get the token.
  • Verified by inspection against the adjacent getToken guard. extension/ has no automated test harness in the repo today, and bun test doesn't cover extension/, so Tier 1 stays green.

Happy to rebase, or to factor the shared sender.tab guard into a helper alongside getToken if you'd prefer that over duplicating the check.

🤖 Generated with Claude Code

The getPort message handler returned the localhost auth token to every
caller, including content scripts, while the sibling getToken handler
deliberately rejects content-script contexts (sender.tab is set for
content scripts). A content script injected into a page could therefore
obtain the token getToken is careful to protect.

Apply the same sender.tab guard to getPort: port and connected stay
available to any extension context, but the auth token is withheld from
content-script callers. Mirrors the existing getToken behavior; no other
behavior changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jbetala7
Copy link
Copy Markdown
Contributor

jbetala7 commented Jun 2, 2026

Validated on current main (3bef43bc) — the bug is live and this fix is complete.

Live bug. extension/background.js has two onMessage handlers that can hand back the localhost auth token. getToken (L326-332) already guards content-script callers (sender.tab set -> { token: null }), but getPort (L301-302) unconditionally returns token: authToken in its payload. So a content script just calls getPort and reads the exact token the getToken guard is protecting.

Completeness. Those two are the only onMessage paths that return the token to a caller. Every other authToken reference (L145 / L165 / L252 / L455) is an Authorization: Bearer header on a localhost fetch issued from the background context, not a value returned to a content script. Mirroring the sender.tab guard into getPort (your diff) therefore closes the leak with no remaining token-return path.

No competing open PR touches extension/background.js, and #1788 (the prior version) is closed, so this is the canonical fix. LGTM.

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.

2 participants