{"id":"GHSA-mx9r-x6ww-qjw9","kind":"vulnerability","aliases":["GHSA-mx9r-x6ww-qjw9"],"related":[],"title":"@better-auth/sso: Personal SSO providers can sign in as another provider's users","description":"## Am I affected?\n\nYou may be affected if you use `@better-auth/sso` `1.7.0-rc.2` through `1.7.0-rc.6` or `1.7.0` through `1.7.2`, and all of these conditions hold:\n\n- An attacker can register a personal SSO provider or use one they registered earlier. Registration is enabled by default for signed-in users, with a limit of 10 providers each.\n- Your application has not configured `resolveUser`.\n- A victim's account is linked through another OpenID Connect (OIDC) or SAML provider, and the attacker can reproduce that provider's identity and the victim's account identifier.\n\nConfiguring `resolveUser` requires an exact provider match and blocks this path. Setting `providersLimit: 0` only stops new registrations; existing providers remain usable.\n\n## Summary\n\nThe SSO plugin lets signed-in users register an OIDC or SAML provider. In affected versions, sign-in through a personal provider could match an account linked through a different provider and create a session for that account.\n\n## Impact\n\nAn attacker with a Better Auth account can register a provider that copies a real provider's identity and reproduces a victim's user identifier. Better Auth then creates a new session for the victim's account without victim interaction.\n\nThe attack does not compromise the real identity provider or steal the victim's existing session.\n\n## Patches\n\nUpgrade `@better-auth/sso` to `1.7.3` or later. The fix prevents one provider from matching an account linked through another provider.\n\n## Workarounds\n\nIf you cannot upgrade now, block SSO sign-in at your application boundary until you can install the fixed release.\n\nSetting `providersLimit: 0` prevents new personal-provider registration but does not disable providers that users already registered. If you keep SSO sign-in available, audit existing personal providers and remove any untrusted registrations. If you cannot verify that inventory, registration limits alone are only a partial mitigation.\n\nIf you already set `resolveUser`, the affected sign-in path requires an exact provider match. Upgrading is still the recommended fix.\n\n## Technical details\n\nAffected versions found linked accounts by the provider's issuer (the OIDC issuer or SAML entity ID) and the account identifier from the sign-in (the OIDC subject or SAML NameID). The lookup did not also check that the account belonged to the `providerId` that handled the sign-in.\n\nAn attacker could register a personal provider with the same OIDC issuer or SAML entity ID as a legitimate provider. The attacker still controlled the new provider's endpoints or signing keys, so it could assert the subject or NameID of an account linked through the legitimate provider. Because the lookup did not enforce the `providerId` boundary, Better Auth treated the victim's account as belonging to the attacker's provider and created a session for the victim. The assertion was valid for the attacker's provider, but it did not prove control of the legitimate provider's account namespace.\n\nVersion `1.7.3` restores account lookup using both the registered `providerId` and the asserted account identifier.","summary":"In affected versions of the @better-auth/sso npm package, a signed-in user can register a personal SSO provider that copies a real provider's issuer and then match accounts linked through that real provider. Better Auth creates a session for the victim's account without victim interaction.","severity":"high","cvss":8.1,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"@better-auth/sso","fixed":["1.7.3"],"affected":">= 1.7.0-rc.2, < 1.7.0","ecosystem":"npm"},{"name":"@better-auth/sso","fixed":["1.7.3"],"affected":">= 1.7.0, < 1.7.3","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["better-auth","cwe-287","cwe-345","node","oidc","package","saml","sso","typescript"],"not_affected_if":["resolveuser-configured","sso-not-used","version-1.7.3-or-later"],"how_to_check":"- Check the installed version with `npm ls @better-auth/sso`; affected versions are `1.7.0-rc.2` through `1.7.0-rc.6` and `1.7.0` through `1.7.2`.\n- Check whether the application sets `resolveUser` in the SSO plugin configuration; without it the exposed path is open.\n- Check whether personal SSO provider registration is enabled (default for signed-in users, up to 10 providers each).","fix":"- `@better-auth/sso` `1.7.3`\n- Setting `providersLimit: 0` only stops new registrations and does not remove existing providers.","status":"open","published_at":"2026-09-29T18:48:44+00:00","first_seen_at":"2026-11-09T22:53:20+00:00","triaged_at":"2026-11-09T22:59:13+00:00","updated_at":"2026-11-09T22:59:13+00:00","category":"package","confidence":0.85,"triage":{"at":"2026-11-09T22:59:13Z","model":"claude-haiku-5-5","output":{"fix":"- `@better-auth/sso` `1.7.3`\n- Setting `providersLimit: 0` only stops new registrations and does not remove existing providers.","reach":"internet","title":"Better Auth SSO: personal providers can sign in as other providers' users","impact":"high","summary":"In affected versions of the @better-auth/sso npm package, a signed-in user can register a personal SSO provider that copies a real provider's issuer and then match accounts linked through that real provider. Better Auth creates a session for the victim's account without victim interaction.","audience":"developers","category":"package","nicknames":[],"who_cares":["better-auth","sso","node","typescript","oidc","saml"],"confidence":0.85,"fix_status":"available","needs_auth":"yes","worst_case":"attacker signs in as another user's account on the application","analyst_note":"Product data gives affected ranges and fixed 1.7.3; maintainer advisory states the workarounds.","how_to_check":"- Check the installed version with `npm ls @better-auth/sso`; affected versions are `1.7.0-rc.2` through `1.7.0-rc.6` and `1.7.0` through `1.7.2`.\n- Check whether the application sets `resolveUser` in the SSO plugin configuration; without it the exposed path is open.\n- Check whether personal SSO provider registration is enabled (default for signed-in users, up to 10 providers each).","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["resolveUser-configured","sso-not-used","version-1.7.3-or-later"],"who_is_affected":"Applications that use the @better-auth/sso plugin with personal SSO provider registration enabled and without a resolveUser configuration. Exposure needs a Better Auth account, since the attacker must be able to register a provider. Applications on managed hosting, or that have not enabled SSO, are unlikely to be affected.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"high"},"cost_usd":0.000898,"input_tokens":5574,"output_tokens":681,"severity_before":"high"},"analyst_status":null,"analyst_note":null,"search":"'-287':38B '-345':40B '/sso':4A,29A,33A,55B,111C,318C '0':206C,360C '1.7.0':112C,115C,118C '1.7.2':120C '1.7.3':320C,583C '10':155C 'account':79B,94B,167C,191C,243C,255C,263C,293C,331C,435C,450C,471C,524C,545C,580C,585C,595C 'affect':48B,100C,104C,231C,413C,431C 'alon':401C 'alreadi':374C,409C 'also':467C 'anoth':12A,171C,334C 'applic':159C,349C 'assert':517C,561C,594C 'attack':128C,180C,258C,298C,483C,503C,550C,566C 'audit':384C 'auth':3A,28A,32A,36B,54B,86B,110C,262C,283C,317C,540C 'avail':383C 'belong':472C,547C 'better':2A,27A,31A,35B,53B,85B,109C,261C,282C,316C,539C 'better-auth':1A,26A,30A,34B,52B,108C,315C 'block':201C,342C 'boundari':350C,538C 'cannot':339C,395C 'check':468C 'compromis':301C 'condit':125C 'configur':162C,193C 'connect':173C 'control':505C,574C 'copi':70B,269C 'could':240C,484C,516C 'creat':87B,250C,285C,554C 'cwe':37B,39B 'default':145C 'detail':430C 'differ':247C 'disabl':370C 'earlier':140C 'enabl':143C 'endpoint':510C 'enforc':535C 'entiti':446C,496C 'exact':197C,420C 'exist':211C,311C,385C 'fix':324C,356C,428C 'found':433C 'ghsa':17A,22A 'ghsa-mx9r-x6ww-qjw9':16A,21A 'handl':477C 'hold':126C 'id':447C,497C 'ident':186C,274C,304C 'identifi':192C,281C,451C,596C 'impact':256C 'instal':354C 'interact':97B,296C 'inventori':398C 'issuer':75B,440C,443C,493C 'keep':378C 'key':513C 'later':322C 'legitim':500C,528C,577C 'let':219C 'limit':153C,400C 'link':80B,169C,244C,332C,434C,525C 'lookup':464C,532C,586C 'match':78B,199C,241C,329C,422C 'may':102C 'mitig':406C 'mx9r':18A,23A 'nameid':462C,521C 'namespac':581C 'new':209C,287C,362C,507C 'node':41B 'npm':56B 'oidc':42B,174C,226C,442C,458C,492C 'one':137C,326C 'openid':172C 'packag':43B,57B 'partial':405C 'patch':313C 'path':203C,417C 'person':5A,66B,132C,238C,364C,386C,487C 'personal-provid':363C 'plugin':218C 'prevent':325C,361C 'prove':573C 'provid':7A,13A,68B,73B,84B,134C,156C,177C,184C,198C,212C,229C,239C,248C,267C,272C,305C,327C,335C,365C,371C,387C,421C,438C,488C,501C,508C,529C,552C,568C,578C 'providerid':475C,537C,591C 'providerslimit':205C,359C 'qjw9':20A,25A 'rc.2':113C 'rc.6':116C 'real':72B,83B,271C,303C 'recommend':427C 'regist':64B,130C,139C,224C,265C,375C,485C,590C 'registr':141C,210C,366C,392C,399C 'releas':357C 'remain':213C 'remov':389C 'reproduc':182C,276C 'requir':195C,418C 'resolveus':163C,194C,411C 'restor':584C 'saml':44B,176C,228C,445C,461C,495C 'session':89B,252C,288C,312C,556C 'set':204C,358C,410C 'sign':9A,60B,148C,221C,234C,345C,381C,415C,455C,480C,512C 'sign-in':233C,344C,380C,414C,454C,479C 'signed-in':59B,147C,220C 'sso':6A,45B,67B,133C,217C,343C,379C 'steal':307C 'still':425C,504C 'stop':208C 'subject':459C,519C 'summari':215C 'technic':429C 'treat':541C 'typescript':46B 'untrust':391C 'upgrad':314C,340C,423C 'usabl':214C 'use':107C,136C,587C 'user':15A,62B,150C,223C,280C,373C 'valid':563C 'verifi':396C 'version':49B,232C,432C,582C 'victim':92B,96B,165C,189C,278C,291C,295C,309C,543C,559C 'without':95B,294C 'workaround':336C 'x6ww':19A,24A","nicknames":[],"mitigations":[],"who_affected":"Applications that use the @better-auth/sso plugin with personal SSO provider registration enabled and without a resolveUser configuration. Exposure needs a Better Auth account, since the attacker must be able to register a provider. Applications on managed hosting, or that have not enabled SSO, are unlikely to be affected.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["sso"],"ptokens":["auth","better","sso"],"labels":["betterauth","cwe287","cwe345","high","node","npm","oidc","package","saml","sso","typescript"],"campaign_type":null,"search_a":"'/sso':4A,29A,33A 'anoth':12A 'auth':3A,28A,32A 'better':2A,27A,31A 'better-auth':1A,26A,30A 'ghsa':17A,22A 'ghsa-mx9r-x6ww-qjw9':16A,21A 'mx9r':18A,23A 'person':5A 'provid':7A,13A 'qjw9':20A,25A 'sign':9A 'sso':6A 'user':15A 'x6ww':19A,24A","search_b":"'-287':38B '-345':40B '/sso':55B 'account':79B,94B 'affect':48B 'auth':36B,54B,86B 'better':35B,53B,85B 'better-auth':34B,52B 'copi':70B 'creat':87B 'cwe':37B,39B 'interact':97B 'issuer':75B 'link':80B 'match':78B 'node':41B 'npm':56B 'oidc':42B 'packag':43B,57B 'person':66B 'provid':68B,73B,84B 'real':72B,83B 'regist':64B 'saml':44B 'session':89B 'sign':60B 'signed-in':59B 'sso':45B,67B 'typescript':46B 'user':62B 'version':49B 'victim':92B,96B 'without':95B","search_c":"'/sso':111C,318C '0':206C,360C '1.7.0':112C,115C,118C '1.7.2':120C '1.7.3':320C,583C '10':155C 'account':167C,191C,243C,255C,263C,293C,331C,435C,450C,471C,524C,545C,580C,585C,595C 'affect':100C,104C,231C,413C,431C 'alon':401C 'alreadi':374C,409C 'also':467C 'anoth':171C,334C 'applic':159C,349C 'assert':517C,561C,594C 'attack':128C,180C,258C,298C,483C,503C,550C,566C 'audit':384C 'auth':110C,262C,283C,317C,540C 'avail':383C 'belong':472C,547C 'better':109C,261C,282C,316C,539C 'better-auth':108C,315C 'block':201C,342C 'boundari':350C,538C 'cannot':339C,395C 'check':468C 'compromis':301C 'condit':125C 'configur':162C,193C 'connect':173C 'control':505C,574C 'copi':269C 'could':240C,484C,516C 'creat':250C,285C,554C 'default':145C 'detail':430C 'differ':247C 'disabl':370C 'earlier':140C 'enabl':143C 'endpoint':510C 'enforc':535C 'entiti':446C,496C 'exact':197C,420C 'exist':211C,311C,385C 'fix':324C,356C,428C 'found':433C 'handl':477C 'hold':126C 'id':447C,497C 'ident':186C,274C,304C 'identifi':192C,281C,451C,596C 'impact':256C 'instal':354C 'interact':296C 'inventori':398C 'issuer':440C,443C,493C 'keep':378C 'key':513C 'later':322C 'legitim':500C,528C,577C 'let':219C 'limit':153C,400C 'link':169C,244C,332C,434C,525C 'lookup':464C,532C,586C 'match':199C,241C,329C,422C 'may':102C 'mitig':406C 'nameid':462C,521C 'namespac':581C 'new':209C,287C,362C,507C 'oidc':174C,226C,442C,458C,492C 'one':137C,326C 'openid':172C 'partial':405C 'patch':313C 'path':203C,417C 'person':132C,238C,364C,386C,487C 'personal-provid':363C 'plugin':218C 'prevent':325C,361C 'prove':573C 'provid':134C,156C,177C,184C,198C,212C,229C,239C,248C,267C,272C,305C,327C,335C,365C,371C,387C,421C,438C,488C,501C,508C,529C,552C,568C,578C 'providerid':475C,537C,591C 'providerslimit':205C,359C 'rc.2':113C 'rc.6':116C 'real':271C,303C 'recommend':427C 'regist':130C,139C,224C,265C,375C,485C,590C 'registr':141C,210C,366C,392C,399C 'releas':357C 'remain':213C 'remov':389C 'reproduc':182C,276C 'requir':195C,418C 'resolveus':163C,194C,411C 'restor':584C 'saml':176C,228C,445C,461C,495C 'session':252C,288C,312C,556C 'set':204C,358C,410C 'sign':148C,221C,234C,345C,381C,415C,455C,480C,512C 'sign-in':233C,344C,380C,414C,454C,479C 'signed-in':147C,220C 'sso':133C,217C,343C,379C 'steal':307C 'still':425C,504C 'stop':208C 'subject':459C,519C 'summari':215C 'technic':429C 'treat':541C 'untrust':391C 'upgrad':314C,340C,423C 'usabl':214C 'use':107C,136C,587C 'user':150C,223C,280C,373C 'valid':563C 'verifi':396C 'version':232C,432C,582C 'victim':165C,189C,278C,291C,295C,309C,543C,559C 'without':294C 'workaround':336C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-09-29T18:48:44+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-mx9r-x6ww-qjw9","url":"https://github.com/better-auth/better-auth/security/advisories/GHSA-mx9r-x6ww-qjw9","severity":"high","published_at":"2026-09-29T18:48:44+00:00","modified_at":"2026-09-29T18:48:44+00:00","first_seen_at":"2026-11-09T22:53:20+00:00","fetched_at":"2026-11-09T22:53:20+00:00","note":null}],"documents":[{"id":110510,"url":"https://github.com/better-auth/better-auth/security/advisories/GHSA-mx9r-x6ww-qjw9","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}