{"id":"CVE-2026-126204","kind":"vulnerability","aliases":["CVE-2026-126204"],"related":[],"title":"express-rate-limit: stale window reset lets clients burst past limit","description":"express-rate-limit is a basic rate-limiting middleware for Express. From 8.6.0 until 8.7.2, the built-in MemoryStore returns a Client whose mutable resetTime object is retained by middleware using skipFailedRequests or skipSuccessfulRequests. When a later request resets the client window, MemoryStore.resetClient mutates that same Date, so an earlier request that finishes or disconnects after the reset can pass the stale-window guard and decrement the current window's count. A client able to keep requests in flight across the boundary can obtain a bounded extra burst of up to one additional configured limit in the new window; the behavior does not increase the sustained rate. Stores that return a fresh Date are not affected. This issue is fixed in version 8.7.2.","summary":"express-rate-limit versions 8.6.0 through 8.7.2 have a bug in the built-in MemoryStore where a request finishing after a window reset can decrement the new window's count. A client that keeps requests in flight across the window boundary can get up to one extra configured limit's worth of requests in the new window, without raising the sustained rate.","severity":"low","cvss":3.7,"epss":null,"exploited":false,"exploited_at":null,"products":[],"ecosystems":[],"tags":["express","node","npm","package","rate-limiting"],"not_affected_if":["custom-store-fresh-date","default-config","other-version"],"how_to_check":"- Check the installed version with `npm ls express-rate-limit`\n- Look for `skipFailedRequests` or `skipSuccessfulRequests` set to true in rate limiter configuration\n- Confirm the store in use is the default MemoryStore, not a custom store that returns a fresh Date","fix":"- `express-rate-limit` `8.7.2`","status":"open","published_at":"2026-11-12T19:16:56+00:00","first_seen_at":"2026-11-12T19:40:13+00:00","triaged_at":"2026-11-12T19:41:01+00:00","updated_at":"2026-11-12T19:41:01+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-12T19:41:01Z","model":"claude-haiku-5-5","output":{"fix":"- `express-rate-limit` `8.7.2`","reach":"internet","title":"express-rate-limit: stale window reset lets clients burst past limit","impact":"low","summary":"express-rate-limit versions 8.6.0 through 8.7.2 have a bug in the built-in MemoryStore where a request finishing after a window reset can decrement the new window's count. A client that keeps requests in flight across the window boundary can get up to one extra configured limit's worth of requests in the new window, without raising the sustained rate.","audience":"developers","category":"package","nicknames":[],"who_cares":["express","npm","node","rate-limiting"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"clients can exceed the rate limit by one extra burst per window","analyst_note":"","how_to_check":"- Check the installed version with `npm ls express-rate-limit`\n- Look for `skipFailedRequests` or `skipSuccessfulRequests` set to true in rate limiter configuration\n- Confirm the store in use is the default MemoryStore, not a custom store that returns a fresh Date","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["default-config","custom-store-fresh-date","other-version"],"who_is_affected":"Applications using express-rate-limit between 8.6.0 and 8.7.2 with the default MemoryStore and skipFailedRequests or skipSuccessfulRequests enabled. Stores that return a fresh Date for the reset time are not affected, and deployments on other versions can skip this.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"low"},"cost_usd":0.000758,"input_tokens":4732,"output_tokens":570,"severity_before":"low"},"analyst_status":null,"analyst_note":null,"search":"'-126204':15A,18A '-2026':14A,17A '8.6.0':31B,104C '8.7.2':33B,106C,216C 'abl':167C 'across':65B,173C 'addit':186C 'affect':209C 'basic':96C 'behavior':194C 'bound':179C 'boundari':68B,175C 'bug':36B 'built':40B,109C 'built-in':39B,108C 'burst':10A,181C 'client':9A,59B,114C,133C,166C 'configur':75B,187C 'count':57B,164C 'current':161C 'cve':13A,16A 'date':139C,206C 'decrement':52B,159C 'disconnect':147C 'earlier':142C 'express':2A,19B,27B,91C,102C 'express-rate-limit':1A,26B,90C 'extra':74B,180C 'finish':46B,145C 'fix':213C 'flight':64B,172C 'fresh':205C 'get':70B 'guard':157C 'increas':197C 'issu':211C 'keep':61B,169C 'later':129C 'let':8A 'limit':4A,12A,25B,29B,76B,93C,99C,188C 'memorystor':42B,111C 'memorystore.resetclient':135C 'middlewar':100C,122C 'mutabl':116C 'mutat':136C 'new':54B,83B,191C 'node':20B 'npm':21B 'object':118C 'obtain':177C 'one':73B,185C 'packag':22B 'pass':152C 'past':11A 'rais':86B 'rate':3A,24B,28B,89B,92C,98C,200C 'rate-limit':23B,97C 'request':45B,62B,80B,130C,143C,170C 'reset':7A,50B,131C,150C 'resettim':117C 'retain':120C 'return':112C,203C 'skipfailedrequest':124C 'skipsuccessfulrequest':126C 'stale':5A,155C 'stale-window':154C 'store':201C 'sustain':88B,199C 'use':123C 'version':30B,215C 'whose':115C 'window':6A,49B,55B,67B,84B,134C,156C,162C,192C 'without':85B 'worth':78B","nicknames":[],"mitigations":[],"who_affected":"Applications using express-rate-limit between 8.6.0 and 8.7.2 with the default MemoryStore and skipFailedRequests or skipSuccessfulRequests enabled. Stores that return a fresh Date for the reset time are not affected, and deployments on other versions can skip this.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":[],"ptokens":[],"labels":["express","low","node","npm","package","ratelimiting"],"campaign_type":null,"search_a":"'-126204':15A,18A '-2026':14A,17A 'burst':10A 'client':9A 'cve':13A,16A 'express':2A 'express-rate-limit':1A 'let':8A 'limit':4A,12A 'past':11A 'rate':3A 'reset':7A 'stale':5A 'window':6A","search_b":"'8.6.0':31B '8.7.2':33B 'across':65B 'boundari':68B 'bug':36B 'built':40B 'built-in':39B 'client':59B 'configur':75B 'count':57B 'decrement':52B 'express':19B,27B 'express-rate-limit':26B 'extra':74B 'finish':46B 'flight':64B 'get':70B 'keep':61B 'limit':25B,29B,76B 'memorystor':42B 'new':54B,83B 'node':20B 'npm':21B 'one':73B 'packag':22B 'rais':86B 'rate':24B,28B,89B 'rate-limit':23B 'request':45B,62B,80B 'reset':50B 'sustain':88B 'version':30B 'window':49B,55B,67B,84B 'without':85B 'worth':78B","search_c":"'8.6.0':104C '8.7.2':106C,216C 'abl':167C 'across':173C 'addit':186C 'affect':209C 'basic':96C 'behavior':194C 'bound':179C 'boundari':175C 'built':109C 'built-in':108C 'burst':181C 'client':114C,133C,166C 'configur':187C 'count':164C 'current':161C 'date':139C,206C 'decrement':159C 'disconnect':147C 'earlier':142C 'express':91C,102C 'express-rate-limit':90C 'extra':180C 'finish':145C 'fix':213C 'flight':172C 'fresh':205C 'guard':157C 'increas':197C 'issu':211C 'keep':169C 'later':129C 'limit':93C,99C,188C 'memorystor':111C 'memorystore.resetclient':135C 'middlewar':100C,122C 'mutabl':116C 'mutat':136C 'new':191C 'object':118C 'obtain':177C 'one':185C 'pass':152C 'rate':92C,98C,200C 'rate-limit':97C 'request':130C,143C,170C 'reset':131C,150C 'resettim':117C 'retain':120C 'return':112C,203C 'skipfailedrequest':124C 'skipsuccessfulrequest':126C 'stale':155C 'stale-window':154C 'store':201C 'sustain':199C 'use':123C 'version':215C 'whose':115C 'window':134C,156C,162C,192C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-29T16:25:00+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L","cvss_by":"security-advisories@github.com","poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-126204","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-126204","severity":null,"published_at":"2026-11-12T19:16:56+00:00","modified_at":"2026-11-12T19:16:56+00:00","first_seen_at":"2026-11-12T19:40:13+00:00","fetched_at":"2026-11-12T19:40:13+00:00","note":null}],"documents":[{"id":137851,"url":"https://github.com/express-rate-limit/express-rate-limit/commit/da5b115b97dd903076d37b19437fbd71445e150b","title":"Patch: github.com","kind":"other","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":137852,"url":"https://github.com/express-rate-limit/express-rate-limit/releases/tag/v8.7.2","title":"Release notes: github.com","kind":"release","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Release notes: github.com"},{"id":137853,"url":"https://github.com/express-rate-limit/express-rate-limit/security/advisories/GHSA-j3cq-92fq-qg5f","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":"2026-10-29T16:25:00+00:00","relation":"advisory","confidence":null,"note":"Vendor 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"}