{
  "same_root_cause": true,
  "confidence": "high",
  "parent_root_cause": "Attacker-controlled OIDC endpoint URLs are persisted without validating that the resolved host is non-internal, and then fetched server-side during the OIDC callback, enabling SSRF.",
  "variant_root_cause": "The 1.6.11 patch only validates the literal hostname (isPublicRoutableHost) at registration time. A public-looking FQDN that resolves to a private IP bypasses the literal check and reaches the same server-side fetch sink during the callback.",
  "shared_sinks": [
    "validateAuthorizationCode (token endpoint) in packages/sso/src/routes/sso.ts",
    "betterFetch (userInfo endpoint) in packages/sso/src/routes/sso.ts"
  ],
  "shared_entry_points": [
    "POST /api/auth/sso/register",
    "POST /api/auth/sign-in/sso",
    "GET /api/auth/sso/callback/:providerId"
  ],
  "difference_from_parent": "The parent used literal internal IP addresses (127.0.0.1) which the 1.6.11 patch blocks. The variant uses a hostname classified as a public FQDN that resolves to a private IP, which the 1.6.11 patch accepts but the 1.6.23 runtime DNS check blocks.",
  "fix_that_closes_both": "Resolve the stored OIDC endpoint hostnames at fetch time and reject any resolved address that is not publicly routable (as implemented in assertEndpointResolvesPublic / assertOIDCEndpointsResolvePublic in @better-auth/sso >= 1.6.23)."
}
