Skip to content

HA token requests never follow a redirect (P1 from the #76 review) - #78

Merged
ThinkOffApp merged 1 commit into
mainfrom
fix/ha-token-no-redirects
Oct 9, 2026
Merged

ThinkOffApp merged 1 commit into
mainfrom
fix/ha-token-no-redirects

Conversation

@ThinkOffApp

Copy link
Copy Markdown
Owner

Fixes the P1 from Codex's review of #76: the Home Assistant token could follow a redirect to any host.

The bug

urllib's default redirect handler builds the next request with the original headers, except the body ones. Authorization is carried over. If the private Home Assistant, or a reverse proxy in front of it, answers 30x to another host, CarWatch sends the long-lived HA token there. That host never passed _is_private_ha.

Measured with the new negative-control test: Python 3.11, 3.12 (our CI) and 3.13 forward the token; 3.14 drops it on its own for a cross-origin redirect.

The fix

  • carwatch/tokenhttp.py: an opener that refuses redirects. It raises HTTPError with the 30x code and the target instead of following.
  • radiation.read_ha sends every token request through it, and reports a redirect plainly: "set radiation.ha.url to the final address".
  • Same bug, two more places: mercedesme._get and _post send the same HA token and now use tokenhttp too. _post was also missing the private-host check that _get has; it has it now.

Tests

  • tests/test_tokenhttp.py, two local servers: HOME redirects (302), OTHER records every Authorization it sees.
    • Negative control: plain urllib carries the token to OTHER, for GET and POST.
    • tokenhttp, mercedesme._get and mercedesme._post must refuse, and OTHER must see nothing.
    • _post refuses a public HA URL before connecting.
  • tests/test_radiation.py: a redirect reads as a redirect error, not "unreachable", and the token reaches only the configured private HA.
  • Reverting either module's switch makes its tests fail. Full suite on 3.12: 235 tests OK.

Not in this PR

room.py sends the GroupMind key (X-API-Key) to https://groupmind.one, which does not redirect. It's lower risk and a separate decision.

🤖 Generated with Claude Code

Codex's review of #76 (P1): urllib's default redirect handler carries every
header except the body ones to the next request, Authorization included. So if
the private Home Assistant, or the proxy in front of it, answered 30x to another
host, CarWatch sent the long-lived HA token to a host that never passed
_is_private_ha. Measured: Python 3.11, 3.12 (CI) and 3.13 forward it; 3.14
already drops it on a cross-origin redirect.

- carwatch/tokenhttp.py: an opener whose redirect handler refuses (HTTPError
  with the 30x code and the target) instead of following.
- radiation.read_ha uses it for every token request, and reports a redirect
  as such ("set radiation.ha.url to the final address").
- The same bug existed in mercedesme._get and _post, which send the same token:
  both use tokenhttp now. _post also lacked the private-host check that _get
  has; it has it now.
- Tests: test_tokenhttp.py with two local servers (HOME redirects, OTHER logs
  every Authorization it sees). A negative control shows plain urllib carrying
  the token to OTHER; tokenhttp, radiation and both Mercedes calls must refuse,
  and OTHER must see nothing. Reverting either module's switch makes its tests
  fail. Full suite on 3.12: 235 tests OK.

Not changed: room.py sends the GroupMind key to https://groupmind.one, which
does not redirect; lower risk, separate decision.

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

vercel Bot commented Oct 9, 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 Oct 9, 2026 1:26pm UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 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-10-09T13:29:20.436667Z e1faac8 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
ThinkOffApp merged commit dda949b into main Oct 9, 2026
3 checks passed

This branch was successfully deployed

1 active deployment
Preview — e1faac80 Deployed Oct 9, 2026 by vercel[bot]
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