fix(security): reject consent scopes outside the original request
The /consent POST handler trusted the scope values submitted in the form, so a forged consent submission could approve (and persist consent for) scopes that were never part of the originating authorization request — a scope-escalation vector. Intersect the submitted scopes with the originally requested set stored in the session before saving consent and completing the flow. Refs: porchlight-a03 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c52778326e
commit
cdde3e3754
2 changed files with 28 additions and 2 deletions
|
|
@ -338,8 +338,10 @@ async def consent_submit(request: Request) -> Response:
|
|||
return RedirectResponse(f"{redirect_uri}?{params}", status_code=303)
|
||||
return HTMLResponse("<h1>Error</h1><p>Invalid action</p>", status_code=400)
|
||||
|
||||
# Allow — collect approved scopes
|
||||
approved_scopes: list[str] = [str(s) for s in form.getlist("scope")]
|
||||
# Allow — collect approved scopes, rejecting anything outside the
|
||||
# originally requested set (a forged form must not escalate scope).
|
||||
requested_scopes = set(auth_params.get("scope", "openid").split())
|
||||
approved_scopes: list[str] = [str(s) for s in form.getlist("scope") if str(s) in requested_scopes]
|
||||
if "openid" not in approved_scopes:
|
||||
approved_scopes = ["openid", *list(approved_scopes)]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue