{"id":"GHSA-fvxx-76fc-893x","kind":"vulnerability","aliases":["GHSA-fvxx-76fc-893x"],"related":[],"title":"better-auth: Revoked sessions can stay valid with secondary storage or the cookie cache","description":"## Am I affected?\n\nYou are affected if you use `better-auth` with **any** of these:\n\n- `secondaryStorage`, from 0.8.1-beta.5.\n- `session.cookieCache` with passkey registration, device authorization, or passwordless two-factor enrollment, from 1.6.25.\n\n## Summary\n\n**Bulk revocation.** With secondary storage, two session changes at the same time could drop a session from the user's session list. Revoking all sessions or banning the user then missed it.\n\n**Cached sessions.** With the cookie cache, a revoked session keeps working until the cache `maxAge` ends, which is documented. Some features accepted that cached session to create a passkey or a new stored session that outlived the cache.\n\n## Impact\n\nBoth problems need an attacker who already holds a valid session for the account. They let that attacker keep access after the session is revoked. Neither problem gives access to an account without credentials.\n\n## Patches\n\nUpgrade `better-auth` and `@better-auth/passkey` to 1.7.16, or to 1.8.0-beta.5 on the beta line.\n\nPasskey registration, device authorization, two-factor enrollment and verification, social account linking, and phone number changes now check the session store, even with the cookie cache on. On 1.7.16, sessions created from API keys are refused on these routes, except two-factor enrollment and phone number changes. On 1.8.0-beta.5, they are refused on all of them.\n\n## Workarounds\n\nTurn off `session.cookieCache` if revocation must take effect immediately. For bulk revocation, stop using `secondaryStorage` until you upgrade.\n\n## Technical details\n\nThe secondary storage session list is updated by reading and writing it in two steps, so concurrent writers could drop a token. Bulk revocation now also records a cutoff time, and sessions created before it count as revoked even when the list missed them. The affected routes now read the session from the store instead of the cookie cache before creating a lasting credential or session.","summary":"Sessions revoked in better-auth can keep working when secondary storage is used or when the session cookie cache is on, and some routes accept a cached session to create new lasting credentials. An attacker who already holds a valid session for an account can keep access after it is revoked, but cannot get in without credentials.","severity":"medium","cvss":4.2,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"better-auth","fixed":["1.7.16"],"affected":">= 0.8.1-beta.5, < 1.7.16","ecosystem":"npm"},{"name":"better-auth","fixed":["1.8.0-beta.5"],"affected":">= 1.8.0-beta.0, < 1.8.0-beta.5","ecosystem":"npm"},{"name":"@better-auth/passkey","fixed":["1.7.16"],"affected":">= 1.6.25, < 1.7.16","ecosystem":"npm"},{"name":"@better-auth/passkey","fixed":["1.8.0-beta.5"],"affected":">= 1.8.0-beta.0, < 1.8.0-beta.5","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["@better-auth/passkey","better-auth","cwe-362","cwe-613","node","package","typescript"],"not_affected_if":["auth-required","cookie-cache-off","no-secondary-storage"],"how_to_check":"- Check the installed version with `npm ls better-auth @better-auth/passkey`.\n- Search your auth configuration for `secondaryStorage` and `cookieCache`.\n- Check whether your app uses passkey registration, device authorization, or passwordless two-factor enrollment.","fix":"- `better-auth` `1.7.16` (from `>= 0.8.1-beta.5, < 1.7.16`), or `1.8.0-beta.5` on the beta line (from `>= 1.8.0-beta.0, < 1.8.0-beta.5`).\n- `@better-auth/passkey` `1.7.16` (from `>= 1.6.25, < 1.7.16`), or `1.8.0-beta.5` on the beta line.\n- Workaround until upgrade: turn off `session.cookieCache` if revocation must be immediate, and stop using `secondaryStorage` for bulk revocation.","status":"open","published_at":"2026-11-03T21:40:04+00:00","first_seen_at":"2026-11-09T22:53:20+00:00","triaged_at":"2026-11-09T22:57:15+00:00","updated_at":"2026-11-09T22:57:15+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T22:57:15Z","model":"claude-haiku-5-5","output":{"fix":"- `better-auth` `1.7.16` (from `>= 0.8.1-beta.5, < 1.7.16`), or `1.8.0-beta.5` on the beta line (from `>= 1.8.0-beta.0, < 1.8.0-beta.5`).\n- `@better-auth/passkey` `1.7.16` (from `>= 1.6.25, < 1.7.16`), or `1.8.0-beta.5` on the beta line.\n- Workaround until upgrade: turn off `session.cookieCache` if revocation must be immediate, and stop using `secondaryStorage` for bulk revocation.","reach":"internet","title":"better-auth: revoked sessions can stay valid via secondary storage or cookie cache","impact":"medium","summary":"Sessions revoked in better-auth can keep working when secondary storage is used or when the session cookie cache is on, and some routes accept a cached session to create new lasting credentials. An attacker who already holds a valid session for an account can keep access after it is revoked, but cannot get in without credentials.","audience":"developers","category":"package","nicknames":[],"who_cares":["better-auth","@better-auth/passkey","node","typescript"],"confidence":0.8,"fix_status":"available","needs_auth":"yes","worst_case":"Revoked sessions remain usable, letting a prior session holder keep account access.","analyst_note":"","how_to_check":"- Check the installed version with `npm ls better-auth @better-auth/passkey`.\n- Search your auth configuration for `secondaryStorage` and `cookieCache`.\n- Check whether your app uses passkey registration, device authorization, or passwordless two-factor enrollment.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["no-secondary-storage","cookie-cache-off","auth-required"],"who_is_affected":"Applications that use better-auth with secondaryStorage (from 0.8.1-beta.5) or with session.cookieCache plus passkey registration, device authorization, or passwordless two-factor enrollment (from 1.6.25). Apps without secondary storage and without the cookie cache enabled are not exposed to the revocation gap, and the attacker must already hold a valid session.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000929,"input_tokens":5326,"output_tokens":792,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-362':48B '-613':50B '/passkey':35A,39A,43B,261C '0.8.1':130C '1.6.25':145C '1.7.16':263C,301C '1.8.0':266C,322C '76fc':19A,24A '893x':20A,25A 'accept':79B,200C 'access':101B,237C,246C 'account':98B,231C,249C,283C 'affect':114C,117C,397C 'alreadi':91B,224C 'also':377C 'api':305C 'attack':89B,222C,235C 'auth':3A,28A,31A,34A,38A,42B,46B,59B,123C,256C,260C 'author':137C,275C 'ban':173C 'beta':270C 'beta.5':131C,267C,323C 'better':2A,27A,30A,33A,37A,41B,45B,58B,122C,255C,259C 'better-auth':1A,26A,29A,32A,36A,40B,44B,57B,121C,254C,258C 'bulk':147C,342C,374C 'cach':15A,73B,81B,179C,184C,192C,202C,216C,298C,410C 'cannot':107B 'chang':154C,288C,320C 'check':290C 'concurr':368C 'cooki':14A,72B,183C,297C,409C 'could':159C,370C 'count':387C 'creat':84B,205C,303C,384C,412C 'credenti':87B,111B,251C,415C 'cutoff':380C 'cwe':47B,49B 'detail':351C 'devic':136C,274C 'document':197C 'drop':160C,371C 'effect':339C 'end':194C 'enrol':143C,279C,316C 'even':294C,390C 'except':312C 'factor':142C,278C,315C 'featur':199C 'fvxx':18A,23A 'get':108B 'ghsa':17A,22A 'ghsa-fvxx-76fc-893x':16A,21A 'give':245C 'hold':92B,225C 'immedi':340C 'impact':217C 'instead':406C 'keep':61B,100B,188C,236C 'key':306C 'last':86B,414C 'let':233C 'line':271C 'link':284C 'list':168C,356C,393C 'maxag':193C 'miss':177C,394C 'must':337C 'need':220C 'neither':243C 'new':85B,210C 'node':51B 'number':287C,319C 'outliv':214C 'packag':52B 'passkey':134C,207C,272C 'passwordless':139C 'patch':252C 'phone':286C,318C 'problem':219C,244C 'read':360C,400C 'record':378C 'refus':308C,326C 'registr':135C,273C 'revoc':148C,336C,343C,375C 'revok':4A,55B,105B,169C,186C,242C,389C 'rout':78B,311C,398C 'secondari':10A,64B,150C,353C 'secondarystorag':128C,346C 'session':5A,54B,71B,82B,95B,153C,162C,167C,171C,180C,187C,203C,212C,228C,240C,292C,302C,355C,383C,402C,417C 'session.cookiecache':132C,334C 'social':282C 'stay':7A 'step':366C 'stop':344C 'storag':11A,65B,151C,354C 'store':211C,293C,405C 'summari':146C 'take':338C 'technic':350C 'time':158C,381C 'token':373C 'turn':332C 'two':141C,152C,277C,314C,365C 'two-factor':140C,276C,313C 'typescript':53B 'updat':358C 'upgrad':253C,349C 'use':67B,120C,345C 'user':165C,175C 'valid':8A,94B,227C 'verif':281C 'without':110B,250C 'work':62B,189C 'workaround':331C 'write':362C 'writer':369C","nicknames":[],"mitigations":[],"who_affected":"Applications that use better-auth with secondaryStorage (from 0.8.1-beta.5) or with session.cookieCache plus passkey registration, device authorization, or passwordless two-factor enrollment (from 1.6.25). Apps without secondary storage and without the cookie cache enabled are not exposed to the revocation gap, and the attacker must already hold a valid session.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["betterauth","passkey"],"ptokens":["auth","better","passkey"],"labels":["betterauth","cwe362","cwe613","medium","node","npm","package","passkey","typescript"],"campaign_type":null,"search_a":"'/passkey':35A,39A '76fc':19A,24A '893x':20A,25A 'auth':3A,28A,31A,34A,38A 'better':2A,27A,30A,33A,37A 'better-auth':1A,26A,29A,32A,36A 'cach':15A 'cooki':14A 'fvxx':18A,23A 'ghsa':17A,22A 'ghsa-fvxx-76fc-893x':16A,21A 'revok':4A 'secondari':10A 'session':5A 'stay':7A 'storag':11A 'valid':8A","search_b":"'-362':48B '-613':50B '/passkey':43B 'accept':79B 'access':101B 'account':98B 'alreadi':91B 'attack':89B 'auth':42B,46B,59B 'better':41B,45B,58B 'better-auth':40B,44B,57B 'cach':73B,81B 'cannot':107B 'cooki':72B 'creat':84B 'credenti':87B,111B 'cwe':47B,49B 'get':108B 'hold':92B 'keep':61B,100B 'last':86B 'new':85B 'node':51B 'packag':52B 'revok':55B,105B 'rout':78B 'secondari':64B 'session':54B,71B,82B,95B 'storag':65B 'typescript':53B 'use':67B 'valid':94B 'without':110B 'work':62B","search_c":"'/passkey':261C '0.8.1':130C '1.6.25':145C '1.7.16':263C,301C '1.8.0':266C,322C 'accept':200C 'access':237C,246C 'account':231C,249C,283C 'affect':114C,117C,397C 'alreadi':224C 'also':377C 'api':305C 'attack':222C,235C 'auth':123C,256C,260C 'author':137C,275C 'ban':173C 'beta':270C 'beta.5':131C,267C,323C 'better':122C,255C,259C 'better-auth':121C,254C,258C 'bulk':147C,342C,374C 'cach':179C,184C,192C,202C,216C,298C,410C 'chang':154C,288C,320C 'check':290C 'concurr':368C 'cooki':183C,297C,409C 'could':159C,370C 'count':387C 'creat':205C,303C,384C,412C 'credenti':251C,415C 'cutoff':380C 'detail':351C 'devic':136C,274C 'document':197C 'drop':160C,371C 'effect':339C 'end':194C 'enrol':143C,279C,316C 'even':294C,390C 'except':312C 'factor':142C,278C,315C 'featur':199C 'give':245C 'hold':225C 'immedi':340C 'impact':217C 'instead':406C 'keep':188C,236C 'key':306C 'last':414C 'let':233C 'line':271C 'link':284C 'list':168C,356C,393C 'maxag':193C 'miss':177C,394C 'must':337C 'need':220C 'neither':243C 'new':210C 'number':287C,319C 'outliv':214C 'passkey':134C,207C,272C 'passwordless':139C 'patch':252C 'phone':286C,318C 'problem':219C,244C 'read':360C,400C 'record':378C 'refus':308C,326C 'registr':135C,273C 'revoc':148C,336C,343C,375C 'revok':169C,186C,242C,389C 'rout':311C,398C 'secondari':150C,353C 'secondarystorag':128C,346C 'session':153C,162C,167C,171C,180C,187C,203C,212C,228C,240C,292C,302C,355C,383C,402C,417C 'session.cookiecache':132C,334C 'social':282C 'step':366C 'stop':344C 'storag':151C,354C 'store':211C,293C,405C 'summari':146C 'take':338C 'technic':350C 'time':158C,381C 'token':373C 'turn':332C 'two':141C,152C,277C,314C,365C 'two-factor':140C,276C,313C 'updat':358C 'upgrad':253C,349C 'use':120C,345C 'user':165C,175C 'valid':227C 'verif':281C 'without':250C 'work':189C 'workaround':331C 'write':362C 'writer':369C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-03T21:40:04+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-fvxx-76fc-893x","url":"https://github.com/better-auth/better-auth/security/advisories/GHSA-fvxx-76fc-893x","severity":"medium","published_at":"2026-11-03T21:40:04+00:00","modified_at":"2026-11-03T22:05:45+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":110499,"url":"https://github.com/better-auth/better-auth/security/advisories/GHSA-fvxx-76fc-893x","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"}