Skip to content

fix(api): keep configured headers on their own origin - #196

Merged
tina4stack merged 1 commit into
tina4stack:v3from
MichaelC8E:fix/api-client-keeps-credentials-on-their-origin
Oct 3, 2026
Merged

tina4stack merged 1 commit into
tina4stack:v3from
MichaelC8E:fix/api-client-keeps-credentials-on-their-origin

Conversation

@MichaelC8E

Copy link
Copy Markdown
Contributor

The Api client sends headers configured on it (constructor headers, add_headers/addHeaders) to other origins. A header can carry a credential under any name, such as X-Api-Key, but only Authorization and Cookie were held back from another origin. So a configured X-Api-Key went to an absolute off-origin URL and onto a redirect to another host, and a per-call header followed a cross-origin redirect too. This builds on the Authorization/Cookie fix in GHSA-m4rj-2p76-3p8v.

Change. Configured headers are now bound to the base origin, like the token. An absolute target on another origin, and a cross-origin redirect hop, carry only User-Agent, Accept, Accept-Encoding, Accept-Language, Content-Type and Content-Length. A client with no base URL keeps sending its headers to the URL each call names, and drops them on a redirect to another origin. The allowlist is the same six names, case-insensitive, in all four ports.

Checked. A 45-case matrix against real listeners (301/302/303/307/308 with GET and POST; host, scheme and port changes; A to B to A; upper-case, protocol-relative, userinfo and backslash targets; a base with a path; no base; upload, download and stream; per-call headers; the cookie jar). On 3.13.144 the leak shows in 21 to 27 of them per port; with this change it shows in none, and every same-origin and no-base control keeps its header.

Tests. tests/test_api_cross_origin_token.py gains 4 cases; 4 of its 16 fail on v3, all pass here. Python never follows a 307/308 POST (urllib), as before. Each of the three parts of the fix (redirect keep-list, initial-target binding, no-base guard) was broken on its own in a copy, and the file went red every time.

Suite. Failing set identical to v3. tests/test_swagger_contract.py is skipped on both because openapi_spec_validator is not installed in the venv.

Metrics. tina4 metrics --fail-on-regression (3.8.95): no regression.

Behaviour changes.

  • On A to B to A the key does not come back at A.
  • Any header outside the six names is dropped on a cross-origin hop, such as Range, If-None-Match and X-Request-Id.
  • An http to https redirect on the same host is cross-origin, so a client that sends an X-Api-Key behind one now gets a 401 instead of the key being forwarded. requests, curl and Go only strip auth and cookie headers, so this is stricter than all three.

Docs. docs/python/21-api-client.md:106,130 say headers are 'sent with every request'; a docs PR updates them.

Parity. Same fix in tina4-php, tina4-python, tina4-ruby and tina4-nodejs.

A header configured on the client (constructor headers, add_headers) can
carry a credential under any name, such as X-Api-Key. Only Authorization
and Cookie were held back from another origin, so every other configured
header went to an absolute off-origin target and onto a cross-origin
redirect hop, and a per-call header followed a cross-origin redirect too.

Configured headers are now bound to the base origin like the token: an
absolute target on another origin gets only content-negotiation headers
(User-Agent, Accept, Accept-Encoding, Accept-Language, Content-Type,
Content-Length), and a cross-origin redirect hop carries only those. A
client with no base keeps sending its headers to the URL each call names,
and drops them on a redirect to another origin.

Signed-off-by: Michael <[email protected]>
@MichaelC8E

Copy link
Copy Markdown
Contributor Author

I have read the Tina4 Contributor Licence Agreement and I agree to it.

@MichaelC8E MichaelC8E closed this Oct 2, 2026
@MichaelC8E MichaelC8E reopened this Oct 2, 2026
@tina4stack
tina4stack merged commit a2efbc2 into tina4stack:v3 Oct 3, 2026
20 of 21 checks passed
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