{
  "id": "security/oauth2-redirect-uri-path-traversal",
  "signature": "OAuth2 redirect_uri path traversal allows open redirect to attacker domain",
  "signature_zh": "OAuth2重定向URI路径遍历允许开放重定向到攻击者域名",
  "regex": "redirect_uri.*(?:%2e%2e%2f|%2e%2e\\\\|\\.\\./|\\.\\.\\\\).*",
  "domain": "security",
  "category": "auth_error",
  "subcategory": null,
  "root_cause": "OAuth2 provider validates redirect_uri only by prefix match, allowing attacker to use a registered callback URL with a path traversal suffix like ../evil.com to redirect to an external domain.",
  "root_cause_type": "generic",
  "root_cause_zh": "OAuth2提供者仅通过前缀匹配验证redirect_uri，允许攻击者使用注册的回调URL并附加路径遍历后缀如../evil.com重定向到外部域名。",
  "versions": [
    {
      "version": "Spring Security OAuth2 2.5.0",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    },
    {
      "version": "OAuth2 Proxy 7.4.0",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    },
    {
      "version": "Keycloak 21.0.0",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    },
    {
      "version": "Apache Oltu 1.0.2",
      "introduced": null,
      "deprecated": null,
      "removed": null,
      "behavior_change": null,
      "status": "active"
    }
  ],
  "os_specific": {},
  "dead_ends": [
    {
      "action": "",
      "why_fails": "Does not fix the root cause; attacker can still use path traversal on any registered URI.",
      "fail_rate": 0.95,
      "condition": "",
      "sources": []
    },
    {
      "action": "",
      "why_fails": "Attackers can use URL encoding (%2e%2e%2f) or double encoding to bypass simple character blacklists.",
      "fail_rate": 0.8,
      "condition": "",
      "sources": []
    },
    {
      "action": "",
      "why_fails": "Does not address the validation logic; timeout is unrelated to redirect URI validation.",
      "fail_rate": 1.0,
      "condition": "",
      "sources": []
    }
  ],
  "workarounds": [
    {
      "action": "Use exact URI matching instead of prefix matching: verify that the redirect_uri exactly matches one of the registered URIs, including path and query parameters. Example in Python with Flask-OAuthlib: 'if redirect_uri not in client.redirect_uris: raise InvalidRedirectURI()'",
      "success_rate": 0.92,
      "how": "Use exact URI matching instead of prefix matching: verify that the redirect_uri exactly matches one of the registered URIs, including path and query parameters. Example in Python with Flask-OAuthlib: 'if redirect_uri not in client.redirect_uris: raise InvalidRedirectURI()'",
      "condition": "",
      "sources": []
    },
    {
      "action": "Normalize the redirect_uri before validation: decode URL encoding, resolve path traversals, and reject if the normalized URI does not start with the registered base URI. Example: 'from urllib.parse import urlparse, urlunparse; parsed = urlparse(redirect_uri); if '..' in parsed.path: reject'",
      "success_rate": 0.88,
      "how": "Normalize the redirect_uri before validation: decode URL encoding, resolve path traversals, and reject if the normalized URI does not start with the registered base URI. Example: 'from urllib.parse import urlparse, urlunparse; parsed = urlparse(redirect_uri); if '..' in parsed.path: reject'",
      "condition": "",
      "sources": []
    },
    {
      "action": "Use a whitelist of allowed hosts and enforce that redirect_uri's host matches exactly. Combine with path validation to prevent open redirect.",
      "success_rate": 0.85,
      "how": "Use a whitelist of allowed hosts and enforce that redirect_uri's host matches exactly. Combine with path validation to prevent open redirect.",
      "condition": "",
      "sources": []
    }
  ],
  "workarounds_zh": [
    "Use exact URI matching instead of prefix matching: verify that the redirect_uri exactly matches one of the registered URIs, including path and query parameters. Example in Python with Flask-OAuthlib: 'if redirect_uri not in client.redirect_uris: raise InvalidRedirectURI()'",
    "Normalize the redirect_uri before validation: decode URL encoding, resolve path traversals, and reject if the normalized URI does not start with the registered base URI. Example: 'from urllib.parse import urlparse, urlunparse; parsed = urlparse(redirect_uri); if '..' in parsed.path: reject'",
    "Use a whitelist of allowed hosts and enforce that redirect_uri's host matches exactly. Combine with path validation to prevent open redirect."
  ],
  "transition_graph": {
    "leads_to": [],
    "preceded_by": [],
    "frequently_confused_with": []
  },
  "official_doc_url": "https://datatracker.ietf.org/doc/html/rfc6749#section-10.6",
  "official_doc_section": null,
  "error_code": "OAUTH2_REDIRECT_URI_PATH_TRAVERSAL",
  "verification_tier": "ai_generated",
  "confidence": 0.85,
  "fix_success_rate": 0.78,
  "resolvable": "true",
  "first_seen": "2024-03-12",
  "last_confirmed": "2024-06-01",
  "last_updated": "2024-06-01",
  "evidence_count": 1,
  "tags": [],
  "locale": "en",
  "aliases": []
}