{"id":"GHSA-xpv3-w29h-x7cv","summary":"Oauthlib: Timing Attack Vulnerability in PKCE code_verifier Comparison (CWE-208)","details":"## Summary\n\nA timing side-channel vulnerability exists in the PKCE (RFC 7636) implementation \nof the Authorization Code Grant flow. The `code_challenge_method_plain` function \nuses Python's standard `==` operator for string comparison instead of a \nconstant-time comparison function, potentially allowing timing-based attacks.\n\n## Affected Component\n\n- File: `oauthlib/oauth2/rfc6749/grant_types/authorization_code.py`\n- Functions: `code_challenge_method_plain`, `code_challenge_method_s256`\n- Vulnerability Type: CWE-208 (Observable Timing Discrepancy)\n\n## Technical Details\n\nPython's `==` operator uses short-circuit evaluation when comparing strings:\n1. Returns `False` immediately if lengths differ\n2. Compares characters left-to-right, stopping at first mismatch\n\nThis means comparison time varies linearly with the length of the common prefix \nbetween the attacker-supplied verifier and the stored challenge, creating a \nmeasurable timing oracle.\n\n## Proof of Concept\n\nTested locally against oauthlib source (network jitter eliminated to isolate \npure Python execution time):\n\n| Input | Result | Time (10M iterations) |\n|---|---|---|\n| Wrong first char (`B` + `A`*49) | Fast reject | 0.34106s |\n| 49 chars correct (`A`*49 + `B`) | Deep compare | 0.37847s |\n| **Difference** | | **0.03741s** |\n\nThe ~37ms delta over 10M iterations corresponds to nanosecond-level differences \nper call, which are statistically exploitable under controlled conditions.\n\n## Attack Scenario\n\n1. Attacker intercepts `authorization_code` via Custom URI Scheme Hijacking\n2. PKCE blocks token request — attacker lacks `code_verifier`\n3. Attacker sends repeated requests to `/token` endpoint measuring response times\n4. Using timing oracle, attacker recovers `code_verifier` character by character\n5. Attacker obtains Access Token → Account Takeover\n\n\u003e **Note:** Practical exploitability is limited due to the single-use nature of \n\u003e authorization codes and real-world network noise. However, the vulnerable \n\u003e pattern should be corrected as a defense-in-depth measure.\n\n## Recommended Fix\n\nReplace `==` with `hmac.compare_digest()` for constant-time comparison:\n\ncr: Elvin Latifli","aliases":["CVE-2026-49265"],"modified":"2026-09-29T18:15:05.141363721Z","published":"2026-09-29T17:56:31Z","database_specific":{"github_reviewed_at":"2026-09-29T17:56:31Z","nvd_published_at":null,"cwe_ids":["CWE-208"],"severity":"MODERATE","github_reviewed":true},"references":[{"type":"WEB","url":"https://github.com/oauthlib/oauthlib/security/advisories/GHSA-xpv3-w29h-x7cv"},{"type":"WEB","url":"https://github.com/oauthlib/oauthlib/pull/963"},{"type":"WEB","url":"https://github.com/oauthlib/oauthlib/commit/40b0ab56da3682c2484a4b78bbff309f8025d950"},{"type":"PACKAGE","url":"https://github.com/oauthlib/oauthlib"}],"affected":[{"package":{"name":"oauthlib","ecosystem":"PyPI","purl":"pkg:pypi/oauthlib"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.0"},{"fixed":"4.0.0"}]}],"versions":["3.0.0","3.0.1","3.0.2","3.1.0","3.1.1","3.2.0","3.2.1","3.2.2","3.3.0","3.3.1"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-xpv3-w29h-x7cv/GHSA-xpv3-w29h-x7cv.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N"}]}