{ "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 } }