{"id":"GHSA-74fm-fwc7-3fwp","kind":"vulnerability","aliases":["GHSA-74fm-fwc7-3fwp"],"related":[],"title":"`serveStatic` with `allowPercentInPath` still decodes the path a second time, bypassing middleware on static paths","description":"### Summary\n\n`serveStatic` has an opt-in option, `allowPercentInPath`, for serving files whose names contain a literal `%`. With it enabled, the check added for GHSA-5r4p-p66f-jhc7 that rejects a path containing `%` is skipped, and the path is decoded a second time. A crafted request can be routed as one path and served as another, so middleware mounted on a static prefix does not run for a file under that prefix.\n\n### Details\n\nHono decodes the request path once before routing. With a malformed percent-encoded sequence, that decode leaves part of the path encoded, the router matches the encoded form, and the second decode in `serveStatic` resolves the real directory. The option skipped the check without limiting what the second decode may change.\n\n`serveStatic` now accepts a path that still contains `%` only when the second decode changes nothing except `%25`, the escape for a literal `%`. Anything else is treated as not found. File names such as `100%.txt` keep working. The file is still resolved inside the configured root; this is not a traversal outside it.\n\n### Impact\n\nAn unauthenticated attacker may reach static files without the middleware on their prefix running, for example an authentication check. This affects applications that set `allowPercentInPath: true` and mount middleware on part of the directory served by `serveStatic`. The default configuration was fixed in 4.13.11 and is not affected.","summary":"With the opt-in allowPercentInPath option enabled, Hono's serveStatic decodes request paths a second time, so a crafted URL can be routed as one path and served as another. An unauthenticated attacker can reach static files under a prefix without the middleware on that prefix, such as an authentication check, running.","severity":"medium","cvss":5.3,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"hono","fixed":["4.13.18"],"affected":">= 4.13.11, <= 4.13.17","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["bun","cwe-174","deno","hono","node","package","servestatic"],"not_affected_if":["default-config","no-allowpercentinpath","no-middleware-on-static-prefix"],"how_to_check":"- Look for `allowPercentInPath: true` in the `serveStatic` configuration.\n- Check the installed version with `npm ls hono`; affected versions are `4.13.11` through `4.13.17`.\n- Check whether middleware such as auth is mounted on a part of the directory served by `serveStatic`.","fix":"- Upgrade `hono` to `4.13.18`.","status":"open","published_at":"2026-11-11T08:54:19+00:00","first_seen_at":"2026-11-11T08:59:08+00:00","triaged_at":"2026-11-11T09:01:19+00:00","updated_at":"2026-11-11T09:01:19+00:00","category":"package","confidence":0.85,"triage":{"at":"2026-11-11T09:01:19Z","model":"claude-haiku-5-5","output":{"fix":"- Upgrade `hono` to `4.13.18`.","reach":"internet","title":"Hono: serveStatic option lets a crafted path skip middleware on static files","impact":"medium","summary":"With the opt-in allowPercentInPath option enabled, Hono's serveStatic decodes request paths a second time, so a crafted URL can be routed as one path and served as another. An unauthenticated attacker can reach static files under a prefix without the middleware on that prefix, such as an authentication check, running.","audience":"developers","category":"package","nicknames":[],"who_cares":["hono","serveStatic","node","bun","deno"],"confidence":0.85,"fix_status":"available","needs_auth":"no","worst_case":"Static files are served without middleware such as authentication running.","analyst_note":"","how_to_check":"- Look for `allowPercentInPath: true` in the `serveStatic` configuration.\n- Check the installed version with `npm ls hono`; affected versions are `4.13.11` through `4.13.17`.\n- Check whether middleware such as auth is mounted on a part of the directory served by `serveStatic`.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["default-config","no-allowPercentInPath","no-middleware-on-static-prefix"],"who_is_affected":"Applications that use Hono's serveStatic with allowPercentInPath set to true and mount middleware, such as authentication, on a path prefix inside the directory it serves. The default configuration was fixed in 4.13.11 and is not affected, so applications without the option can skip it.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000794,"input_tokens":4988,"output_tokens":591,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-174':29B '100':247C '25':230C '3fwp':20A,25A '4.13.11':311C '5r4p':114C '74fm':18A,23A 'accept':216C 'add':110C 'affect':288C,315C 'allowpercentinpath':3A,40B,96C,292C 'anoth':65B,144C 'anyth':236C 'applic':289C 'attack':68B,270C 'authent':85B,285C 'bun':27B 'bypass':11A 'chang':213C,227C 'check':86B,109C,205C,286C 'configur':258C,307C 'contain':102C,121C,221C 'craft':54B,133C 'cwe':28B 'decod':5A,46B,128C,163C,178C,194C,211C,226C 'default':306C 'deno':30B 'detail':161C 'directori':200C,301C 'els':237C 'enabl':42B,107C 'encod':175C,184C,189C 'escap':232C 'exampl':283C 'except':229C 'file':72B,99C,157C,243C,252C,274C 'fix':309C 'form':190C 'found':242C 'fwc7':19A,24A 'ghsa':17A,22A,113C 'ghsa-5r4p-p66f-jhc7':112C 'ghsa-74fm-fwc7-3fwp':16A,21A 'hono':26A,31B,43B,162C 'impact':267C 'insid':256C 'jhc7':116C 'keep':249C 'leav':179C 'limit':207C 'liter':104C,235C 'malform':172C 'match':187C 'may':212C,271C 'middlewar':12A,78B,146C,277C,296C 'mount':147C,295C 'name':101C,244C 'node':32B 'noth':228C 'one':60B,139C 'opt':38B,93C 'opt-in':37B,92C 'option':41B,95C,202C 'outsid':265C 'p66f':115C 'packag':33B 'part':180C,298C 'path':7A,15A,48B,61B,120C,126C,140C,166C,183C,218C 'percent':174C 'percent-encod':173C 'prefix':75B,81B,151C,160C,280C 'reach':70B,272C 'real':199C 'reject':118C 'request':47B,134C,165C 'resolv':197C,255C 'root':259C 'rout':58B,137C,169C 'router':186C 'run':87B,154C,281C 'second':9A,50B,130C,193C,210C,225C 'sequenc':176C 'serv':63B,98C,142C,302C 'servestat':1A,34B,45B,89C,196C,214C,304C 'set':291C 'skip':123C,203C 'static':14A,71B,150C,273C 'still':4A,220C,254C 'summari':88C 'time':10A,51B,131C 'travers':264C 'treat':239C 'true':293C 'txt':248C 'unauthent':67B,269C 'url':55B 'whose':100C 'without':76B,206C,275C 'work':250C","nicknames":[],"mitigations":[],"who_affected":"Applications that use Hono's serveStatic with allowPercentInPath set to true and mount middleware, such as authentication, on a path prefix inside the directory it serves. The default configuration was fixed in 4.13.11 and is not affected, so applications without the option can skip it.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["hono"],"ptokens":["hono"],"labels":["bun","cwe174","deno","hono","medium","node","npm","package","servestatic"],"campaign_type":null,"search_a":"'3fwp':20A,25A '74fm':18A,23A 'allowpercentinpath':3A 'bypass':11A 'decod':5A 'fwc7':19A,24A 'ghsa':17A,22A 'ghsa-74fm-fwc7-3fwp':16A,21A 'hono':26A 'middlewar':12A 'path':7A,15A 'second':9A 'servestat':1A 'static':14A 'still':4A 'time':10A","search_b":"'-174':29B 'allowpercentinpath':40B 'anoth':65B 'attack':68B 'authent':85B 'bun':27B 'check':86B 'craft':54B 'cwe':28B 'decod':46B 'deno':30B 'enabl':42B 'file':72B 'hono':31B,43B 'middlewar':78B 'node':32B 'one':60B 'opt':38B 'opt-in':37B 'option':41B 'packag':33B 'path':48B,61B 'prefix':75B,81B 'reach':70B 'request':47B 'rout':58B 'run':87B 'second':50B 'serv':63B 'servestat':34B,45B 'static':71B 'time':51B 'unauthent':67B 'url':55B 'without':76B","search_c":"'100':247C '25':230C '4.13.11':311C '5r4p':114C 'accept':216C 'add':110C 'affect':288C,315C 'allowpercentinpath':96C,292C 'anoth':144C 'anyth':236C 'applic':289C 'attack':270C 'authent':285C 'chang':213C,227C 'check':109C,205C,286C 'configur':258C,307C 'contain':102C,121C,221C 'craft':133C 'decod':128C,163C,178C,194C,211C,226C 'default':306C 'detail':161C 'directori':200C,301C 'els':237C 'enabl':107C 'encod':175C,184C,189C 'escap':232C 'exampl':283C 'except':229C 'file':99C,157C,243C,252C,274C 'fix':309C 'form':190C 'found':242C 'ghsa':113C 'ghsa-5r4p-p66f-jhc7':112C 'hono':162C 'impact':267C 'insid':256C 'jhc7':116C 'keep':249C 'leav':179C 'limit':207C 'liter':104C,235C 'malform':172C 'match':187C 'may':212C,271C 'middlewar':146C,277C,296C 'mount':147C,295C 'name':101C,244C 'noth':228C 'one':139C 'opt':93C 'opt-in':92C 'option':95C,202C 'outsid':265C 'p66f':115C 'part':180C,298C 'path':120C,126C,140C,166C,183C,218C 'percent':174C 'percent-encod':173C 'prefix':151C,160C,280C 'reach':272C 'real':199C 'reject':118C 'request':134C,165C 'resolv':197C,255C 'root':259C 'rout':137C,169C 'router':186C 'run':154C,281C 'second':130C,193C,210C,225C 'sequenc':176C 'serv':98C,142C,302C 'servestat':89C,196C,214C,304C 'set':291C 'skip':123C,203C 'static':150C,273C 'still':220C,254C 'summari':88C 'time':131C 'travers':264C 'treat':239C 'true':293C 'txt':248C 'unauthent':269C 'whose':100C 'without':206C,275C 'work':250C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-11T08:54:19+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-74fm-fwc7-3fwp","url":"https://github.com/honojs/hono/security/advisories/GHSA-74fm-fwc7-3fwp","severity":"medium","published_at":"2026-11-11T08:54:19+00:00","modified_at":"2026-11-11T08:54:19+00:00","first_seen_at":"2026-11-11T08:59:08+00:00","fetched_at":"2026-11-11T08:59:08+00:00","note":null}],"documents":[{"id":124181,"url":"https://github.com/honojs/hono/security/advisories/GHSA-74fm-fwc7-3fwp","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"}