I'm not convinced, I believe S4 almost always sufficient. And that's the
correct place for improvement. Changing the recommendation doesn't feel
appropriate.

S5: However, I also believe that not everyone can achieve S4, but rather
than S1-S3 if you truly want to handle the auth code exfiltration through
logs, and are concerned about that, then using a BFF is likely the solution
for you. That is require the client secret for auth code exchange rather
than PKCE.

However, part 2. Can we just claim we need to wait for PKCE signed with a
key generated by the user agent through a TPM to solve that rather than
explicitly trying to change the advice?

I don't think the change to another strategy, or recommending revoking of
auth codes which already have a recommendation of less than 1 minute before
they become invalid makes sense. That creates more complexity to get this
right, rather than a fool-proof solution. If we can't implement secrets
sanitization, then I'm not sure a more complex strategy would be correctly
implemented especially at scale where auth codes generation might highly
distributed in nature.

I would highly get behind either TPM or even better a browser based
integration to generate PKCEs outside of the application to block malicious
exchange.

Interestingly enough, this is exactly the problem I've been complaining
that Google's DBSC (device bound sessions credentials) explicitly foils to
handle. If we had a fix to that security vulnerability in DBSC, I believe
(if I understand the concerns in this thread correctly) we'd have a
solution for this problem as well.

On Wed, Nov 5, 2025, 15:00 Neil Madden <[email protected]> wrote:

> OK, I don't think we're going to agree on all the points here, and this
> thread is getting really long. Let me try to summarise and see if there is
> a way forward.
>
> The attack:
> In the case of a CSRF attack against the auth code flow, detected via the
> "state" parameter, the auth code remains unused and valid. If an attacker
> can observe that auth code then they can use it themselves - they can
> control the state and PKCE in the CSRF attack, so those are not sufficient
> countermeasures. (CSRF attack here basically just means getting the user to
> click on a link, as the authorization endpoint allows cross-origin requests
> by design).
>
> The main risks that the code might be exposed are:
>
> R1. In logs on the server or any intermediary, where attacker has
> (near-)real-time access to the logs
> R2. If the client doesn't scrub the URL after the error and the user then
> subsequently copy+pastes it to the attacker
> R3. Referer/window.referrer leakage if the client is explicitly opting in
> to this (i.e., explicitly downgrading the Referrer-Policy - seems unlikely
> to me).
> R4. Third-party scripts (eg analytics) on the callback page. (Not a
> recommended practice, but probably does happen).
>
> The proposed solutions are:
>
> S1. Use response_mode=fragment
>  * Addresses R1 (fragment is not sent to server) and R3 (fragment is not
> included in Referer)
>  * Doesn't address R2, in fact may make it worse (need to explicitly
> include a new fragment in a redirect to get rid of it - see
> https://www.ietf.org/rfc/rfc9700.html#name-redirect-uri-validation-atta)
>  * Partially addresses R4 in that analytics providers don't store the
> fragment by default.
>  * Requires client-side Javascript.
>
> S2. Use response_mode=form-post
>  * Addresses R1 (servers normally don't log POST body) and R3 (post data
> not included in Referer)
>  * Addresses R2 as data is not in the URL at all, and not visible to the
> user.
>  * Addresses R4 too, as analytics scripts also will not collect POST body
> either.
>  * Requires client-side Javascript and SameSite=none cookies (if storing
> the state in a cookie, as is common).
>
> (S1 and S2 are both vulnerable to downgrade attacks as the attacker can
> change it to response_mode=query - would need AS to actively block query
> response).
>
> S3. Ensure auth code is invalidated in case of detected CSRF.
> S3a: Client carries out exchange as normal but then revokes the tokens
> immediately (eg via token revocation endpoint, if supported, or maybe just
> by replaying the auth code itself).
> S3b: Client uses PKCE and relies on the AS revoking the auth code in case
> of PKCE verifier mismatch. Requires AS to enforce PKCE, otherwise downgrade
> possible again.
> * Addresses all risks by explicitly ensuring code/tokens are invalidated
> in case of CSRF.
> * Requires change of client behaviour.
> * May not actually work if AS doesn't implement revocation
> properly/enforce PKCE etc.
>
> S4. Accept the risk, maybe tighten up wording to clarify the risks: eg
> sanitise logs, use short auth code lifetimes, always scrub code from URL
> even in error cases.
> * Relies on existing countermeasures and assume short lifespan of code is
> adequate protection for the level of risk.
> * Do the people who'd need to implement these countermeasures (eg web
> server/proxy admins) read security considerations for new OAuth specs?
> Probably not...
>
> I think you have convinced me that S4 is probably not sufficient. I'm not
> convinced that S1 or S2 are good solutions, although I could maybe get on
> board for S2. S3 is probably the best technical solution, ensuring the code
> is invalidated. However, it seems like a lot of changes across the
> ecosystem would be needed, which does seem a lot given the (IMO) low risk
> of this ever being exploited.
>
> Are there other alternatives? PAR (with client auth) would prevent the
> CSRF attack (again, if enforced by the AS), and I think JAR would too -
> i.e, preventing the CSRF by strongly authenticating auth requests.
>
> Best wishes,
>
> Neil
>
>
>
> _______________________________________________
> OAuth mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
>
_______________________________________________
OAuth mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to