PST-065: The OAuth token-exchange client follows redirects while carrying the client secret and the code #794
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#794
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found in the security audit of 2026-10-10 (
SECURITY-AUDIT-2026-10-10.md), run againstmainatc30851bfrom 8 to 10 October 2026, as PST-065. Severity: Informational.The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it.
src/postulo/plugins/consent.py(240-247)Who can do it, and what they need. A provider (or a plugin-declared token endpoint) that answers the token request with a 307/308 redirect to another origin. Today the shipped token URLs are Google's and Microsoft's fixed endpoints (the user-typed Microsoft tenant only alters the path on login.microsoftonline.com), so no practical …
How it works.
exchange()openshttp.client()(follow_redirects=True, max 3) and POSTsclient_id,client_secretand the grant (codeorrefresh_token) as form data.Authorizationheader on a cross-origin redirect; the form body is re-sent as-is on 307/308, and on 301/302/303 the method becomes GET with no body.Impact. Credential exposure only if a provider endpoint redirects cross-origin, which the two shipped providers do not. Recorded as a hardening note: an OAuth token endpoint should never be followed.
Verification (verdict: confirmed; severity after verification: Informational). Only 307/308 re-send the body; 301/302/303 become a bodiless GET. Precondition (a cross-origin redirect from the real provider, or a plugin-declared token_url) is not attacker-reachable by a user or a stranger; the user-typed Microsoft tenant only changes the path on login.microsoftonline.com. Remediation: call the token endpoint with follow_redirects=False (http.client(follow_redirects=False)) and treat any 3xx as ConsentFailed.
Suggested remediation. Call
http.client(follow_redirects=False)inexchangeand treat any 3xx from a token endpoint as a failure.Fixed in
85629e928on main.