Skip to content

dash: drop wildcard CORS on /api/status, send Referrer-Policy (#12) - #68

Open
ThinkOffApp wants to merge 1 commit into
mainfrom
fix/status-wildcard-cors
Open

ThinkOffApp wants to merge 1 commit into
mainfrom
fix/status-wildcard-cors

Conversation

@ThinkOffApp

Copy link
Copy Markdown
Owner

Partial fix for #12. Found while assessing #12/#13 rather than reported.

The finding

/api/status returns live car facts, the Pi's process list (ps -eo) and the last agent journal lines — and carried:

Access-Control-Allow-Origin: *

That header is inert only while every caller needs a token. On home wifi the dashboard authorises by network instead: _peer_is_owner() trusts any private address once _pi_on_home_wifi() is true — deliberately, so phones at home open the dash without typing anything.

Ambient authority + wildcard CORS means any web page open on a phone on that wifi could fetch this endpoint in the background and read the reply cross-origin.

Why removing it is safe

/api/status is fetched only from the dashboard page itself (same-origin), and it is the only Access-Control-Allow-Origin in the repo. Nothing external consumes it.

Also

Referrer-Policy: no-referrer on the common send path. The token rides in the URL as ?t= so a one-tap link works in the car — which means every outbound link from a dashboard page would otherwise carry the credential in its Referer. That is one of the four leak routes #12 lists and the one that costs nothing to close.

What this does NOT fix

The token still travels in URLs and still gates /api/update, which pulls and runs code (#13). Splitting that into privilege tiers changes how petrus repairs the car from the roadside, and getting it wrong strands him. That needs his decision, not a quiet commit.

Tests

tests/test_dash_headers.py, 4 cases: no wildcard CORS is ever sent (a comment naming it is fine), the referrer policy is sent, the status payload is undisturbed, and — so the premise cannot rot silently — that ambient auth still exists, which is what makes the CORS removal matter.

Suite failure on this branch is test_dash_loop's missing pytest — pre-existing on main, fixed separately in #64.

Not verified on the car

Header-level change verified in source and tests; the car is unreachable, so it has not been exercised against a live dashboard.

🤖 Generated with Claude Code

/api/status returns live car facts, the Pi's process list (ps -eo) and the
last agent journal lines. It carried Access-Control-Allow-Origin: *.

That header is only inert while every caller needs a token. On home wifi the
dashboard authorises by NETWORK instead - _peer_is_owner() trusts any private
address once _pi_on_home_wifi() is true, deliberately, so phones at home open
the dash without one. Ambient authority plus a wildcard CORS header means any
web page open on a phone on that wifi could fetch this endpoint in the
background and READ the reply cross-origin.

The dashboard is same-origin and never needed the header: /api/status is
fetched only from the dash page itself, and it is the sole ACAO in the repo,
so nothing external breaks.

Also adds Referrer-Policy: no-referrer to the common send path. The token
rides in the URL as ?t= so a one-tap link works in the car, which means every
outbound link from a dashboard page would otherwise carry the credential in
its Referer. That is one of the four leak routes #12 lists, and it is the one
that costs nothing to close.

This does not address the rest of #12 or #13: the token still travels in URLs
and still gates /api/update, which pulls and runs code. Splitting that into
tiers changes how petrus repairs the car from the roadside, so it needs his
call rather than a quiet commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
carwatch-dev Ready Ready Preview Sep 18, 2026 5:01pm UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-18T17:04:16.557557Z cc48c91 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThinkOffApp

Copy link
Copy Markdown
Owner Author

Now confirmed against the live car, not just the source.

Reached Vadelma over its own dial-out cloudflared tunnel (the reach_url the presence heartbeat publishes — the channel reach.sh exists for) and requested /api/status:

HTTP/2 200
access-control-allow-origin: *        <- still being sent
(no referrer-policy header)

And the payload is not trivial — it really is the thing worth protecting:

fact keys              10
process list entries     5     (ps -eo)
journal lines            8     (journalctl -u carwatch-agent)

So the finding is observed behaviour on the deployed car, not an inference from reading the handler.

Two honest limits on that check:

  • The wildcard header is confirmed; the exploit path is not, because it needs a request from a device on home wifi where _peer_is_owner() authorises without a token. I authenticated with a token over the tunnel, which is the safe path, so I demonstrated the header and not the ambient-auth combination.
  • HEAD /api/status returns 501 — this server implements no do_HEAD. Worth knowing for anyone probing it; my first check looked like a missing endpoint when it was a missing method.

Read-only throughout: GETs only, nothing written, /api/update untouched.

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