{"id":"CVE-2026-49265","aliases":["GHSA-xpv3-w29h-x7cv","PYSEC-2026-4114"],"url":"https://o3.security/vulnerability/CVE-2026-49265","summary":"OAuthLib: Timing Attack Vulnerability in PKCE code_verifier Comparison","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> **Note:** Practical exploitability is limited due to the single-use nature of \n> authorization codes and real-world network noise. However, the vulnerable \n> 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","published":"2026-10-13T15:47:11.854Z","modified":"2026-10-24T02:30:37.290657663Z","cvss":{"score":6.8,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N"},"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"PyPI","name":"oauthlib","fixedVersion":"4.0.0"}],"fix":{"url":"https://github.com/oauthlib/oauthlib/commit/74664d3fe037a354e180e305135c6bab1747a6b0","label":"oauthlib/oauthlib@74664d3"},"references":[{"type":"WEB","url":"https://github.com/oauthlib/oauthlib/releases/tag/v4.0.0"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/49xxx/CVE-2026-49265.json"},{"type":"ADVISORY","url":"https://github.com/oauthlib/oauthlib/security/advisories/GHSA-xpv3-w29h-x7cv"},{"type":"ADVISORY","url":"https://github.com/pypa/advisory-database/tree/main/vulns/oauthlib/PYSEC-2026-4114.yaml"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-49265"},{"type":"FIX","url":"https://github.com/oauthlib/oauthlib/commit/74664d3fe037a354e180e305135c6bab1747a6b0"},{"type":"FIX","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"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-24T02:30:37.290657663Z"}}