{
  "schema_version": "1.4.0",
  "id": "GHSA-vp58-j275-797x",
  "modified": "2025-03-03T13:44:59Z",
  "published": "2025-02-24T20:49:50Z",
  "aliases": [],
  "summary": "Better Auth allows bypassing the trustedOrigins Protection which leads to ATO",
  "details": "### Summary\nA bypass was found for **wildcard** or **absolute URLs** trustedOrigins configurations and opens the victims website to a **Open Redirect** vulnerability, where it can be used to steal the **reset password token** of a victims account by changing the \"callbackURL\" parameter value to a website owned by the attacker.\n\n### Details\n\n#### Absolute URLs\n\nThe issue here appears in the **middleware**,  [specifically](https://github.com/better-auth/better-auth/blob/ddebd0358d74376ea64541512d0167dd4377f182/packages/better-auth/src/api/middlewares/origin-check.ts#L53). This protection is not sufficiente and it allows attackers to exploit a open redirect vulnerability, by using the payload `/\\/example.com`. We can check this is a valid URL ( or it will be a valid URL because the URL parser fix it for us ), by checking the image bellow:\n\n![image](https://github.com/user-attachments/assets/d192f06d-358d-4612-97d9-cab89ba55b06)\n\n```typescript\n// trustedOrigins = [ \"https://example.com\" ]\nvalidateURL(\"https://attacker.com\", \"callbackURL\") // ❌ APIError, No Redirect\nvalidateURL(\"/\\/attacker.com\", \"callbackURL\")       // ✅ Redirect to http://attacker.com\n```\n\n#### Regex\n\nThe issue here is because the regex is not strong enough `[^/\\\\]*?\\.example\\.com[/\\\\]*?` ( this is the regex it will be created if we have a wildcard as the trustedOrigins config ), but we can bypass by using a payload like:\n\n```text\n// trustedOrigins = [ \"*.example.com\" ]\n  ┌──────────────────┐       ┌────────────────┐       ┌─────────────────┐\n  │ None of [ \"/\\\" ] │ ────▶ │ \".example.com\" │ ────▶ │ One of [ \"/\\\" ] │\n  └──────────────────┘       └────────────────┘       └─────────────────┘\n          demo                  .example.com                    /               ✅ Redirect to https://example.com\n          demo                  .attacker.com                   /               ❌ APIError, no redirect\n   http:attacker.com?           .example.com                    /               ✅ Redirect to http://attacker.com\n````\n\nThis works because **:** and **?** are special chars in a URL, so when the URL parser sees, **http:** it will fix our happily fix our URL to http://attacker.com? and make  `.example.com` as parameter, thus, bypassing this check.\n\n### PoC\nWe can PoC the open redirect by using the `demo.better-auth.com`. \nIf we access the URL bellow, we are redirected to example.com:\n- https://demo.better-auth.com/api/auth/reset-password/x?callbackURL=/\\/example.com\n\n### Impact\nEvery single website using the **better-auth** library, is vulnerable to un-auth open redirect and more importantilly, vulnerable to potential one click account take over vulnerability, as the attacker can send the victim a email to reset their account while changing the \"redirectTo\" parameter [here](https://demo.better-auth.com/forget-password), and when the victim clicks on the link, the reset token is sent to the attackers website, which then a attacker could use that token to reset the password of the victims account.",
  "severity": [
    {
      "type": "CVSS_V4",
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
    }
  ],
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "better-auth"
      },
      "ranges": [
        {
          "type": "ECOSYSTEM",
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.1.21"
            }
          ]
        }
      ],
      "database_specific": {
        "last_known_affected_version_range": "<= 1.1.20"
      }
    }
  ],
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/better-auth/better-auth/security/advisories/GHSA-vp58-j275-797x"
    },
    {
      "type": "WEB",
      "url": "https://github.com/better-auth/better-auth/commit/b381cac7aafd6aa53ef78b6ab771ebfa24643c80"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/better-auth/better-auth"
    },
    {
      "type": "WEB",
      "url": "https://github.com/better-auth/better-auth/blob/ddebd0358d74376ea64541512d0167dd4377f182/packages/better-auth/src/api/middlewares/origin-check.ts#L53"
    }
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-601"
    ],
    "severity": "CRITICAL",
    "github_reviewed": true,
    "github_reviewed_at": "2025-02-24T20:49:50Z",
    "nvd_published_at": null
  }
}