Skip to content

Fix auth token exposure via externally_connectable (#246)#255

Open
boot-coco wants to merge 1 commit intodevelopfrom
fix/246-auth-token-exposure
Open

Fix auth token exposure via externally_connectable (#246)#255
boot-coco wants to merge 1 commit intodevelopfrom
fix/246-auth-token-exposure

Conversation

@boot-coco
Copy link
Contributor

Summary

  • Manifest: Restrict externally_connectable localhost pattern from *://localhost/* to *://localhost:3462/*, preventing arbitrary localhost pages from messaging the extension
  • GET_AUTH_STATE: No longer returns the raw JWT token to external callers; returns { authenticated: boolean, authUser: { name, email } } instead
  • DASHBOARD_LOGIN: Validates the provided token against the server (/api/v2/auth/me) before accepting it into extension storage, preventing arbitrary token injection
  • Dashboard: Removed extension-to-dashboard token auto-sync; dashboard now relies on its own OAuth login flow

Test plan

  • Load unpacked extension, verify popup auth check still works (internal GET_AUTH_STATE unchanged)
  • Open dashboard on localhost:3462, verify OAuth login flow works independently
  • Verify DASHBOARD_LOGIN with a valid token succeeds and syncs to extension
  • Verify DASHBOARD_LOGIN with an invalid/expired token is rejected
  • Verify a page on localhost:9999 cannot send messages to the extension
  • Verify GET_AUTH_STATE from dashboard no longer leaks the JWT token

Closes #246

🤖 Generated with Claude Code

- Restrict externally_connectable localhost to port 3462 only
- GET_AUTH_STATE: return { authenticated, user } instead of raw JWT token
- DASHBOARD_LOGIN: validate token with server before accepting
- Dashboard: remove extension token auto-sync (use own OAuth flow)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@jessie-coco jessie-coco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review R1: CLEAN — 0 P1 + 0 P2 + 1 P3

Reviewed all 4 changed files in full (not just diff hunks). Security fix is well-implemented.

What was checked

Correctness: GET_AUTH_STATE correctly strips the JWT and returns only { authenticated, authUser: { name, email } }. DASHBOARD_LOGIN validates the token server-side via /api/v2/auth/me before calling setAuthState, and uses the server-verified user object instead of trusting message.user. The AUTH_STATE_CHANGED broadcast and { success: true } return only execute on the happy path — early returns in the error/catch branches prevent false-positive notifications.

Security: externally_connectable tightened from *://localhost/* to *://localhost:3462/* — correct. Token no longer exposed to external callers. Server-side token validation prevents arbitrary token injection via DASHBOARD_LOGIN. Dashboard's syncLoginToExtension() (push direction: dashboard → extension) is the correct flow and now validated.

Integration: Dashboard removed extension→dashboard token auto-sync but still pushes its own OAuth token to the extension via syncLoginToExtension. This means the extension stays in sync when the user logs in through the dashboard. The getAuthFromExtension function in api.js is updated to return { user } only. No callers broken.

Edge cases: Empty/null authUser handled via the authenticated boolean gate. getConfig().serverUrl trailing slash stripped consistently. Fetch errors caught and returned as { error } messages.

P3 (non-blocking)

  1. P3: Dead importgetAuthFromExtension is still imported in dashboard/src/main.js (line 18) but no longer called anywhere in the file after the auto-sync removal. Harmless but worth cleaning up.

LGTM. Approving.

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