{"id":"GHSA-4h7h-rv7c-7m2v","kind":"vulnerability","aliases":["GHSA-4h7h-rv7c-7m2v"],"related":[],"title":"`validator('form')` skips validation for `multipart/form-data` requests with extra parameters","description":"### Summary\n\n`validator('form')` only recognizes a `multipart/form-data` `Content-Type` that carries nothing but a single `boundary` parameter. A request with another legal parameter, such as `charset`, or with extra whitespace after the `;` is not recognized as a form. The validation callback then receives an empty object, while `c.req.parseBody()` still parses the body as a form.\n\n### Details\n\nThe check that decides whether a request body is a form was written as a strict pattern over the whole `Content-Type` value. Any parameter list that does not look exactly like `; boundary=...` fails the check. When it fails, the middleware does not read the body and passes an empty object to the validation callback. If the callback accepts an empty object, the request proceeds to the handler, which can still read all submitted fields through `c.req.parseBody()` or `c.req.formData()`.\n\n`application/x-www-form-urlencoded` is not affected. Only the `multipart/form-data` branch has the strict pattern.\n\nThis issue arises when an application relies on `validator('form')` to reject or restrict fields and the validation callback does not fail on an empty object.\n\n### Impact\n\nAn unauthenticated client can send form fields that the `form` validator never sees, by adding a legal parameter to the `Content-Type` header.\n\nThis may lead to:\n\n- Allow-list or required-field checks in the validator being skipped\n- Fields the application intended to reject reaching the handler\n\nThis issue affects applications that use `validator('form')` with `multipart/form-data` requests and whose validation callback accepts an empty object.\n\n### Workarounds\n\nReject an empty object in the `validator('form')` callback, or validate the result of `await c.req.parseBody()` in the handler.","summary":"Hono's validator('form') middleware only recognizes a multipart/form-data Content-Type with a single boundary parameter, so a request adding a charset parameter or extra whitespace is treated as having no form data. The validation callback then receives an empty object while the handler can still read all submitted fields.","severity":"medium","cvss":5.3,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"hono","fixed":["4.13.16"],"affected":">= 4.5.1, <= 4.13.15","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["bun","cloudflare-workers","cwe-20","deno","hono","node","package"],"not_affected_if":["no-validator-form","rejects-empty-object","urlencoded-only"],"how_to_check":"- Run `npm ls hono` in the project and look for a version between `4.5.1` and `4.13.15`\n- Search the code for `validator('form'` to find routes that rely on the form validator\n- Check whether the validation callback would accept an empty object","fix":"- Hono: move to `4.13.16`\n- Workaround from the advisory: reject an empty object in the validator callback, or validate the result of `await c.req.parseBody()` in the handler","status":"open","published_at":"2026-11-01T02:36:54+00:00","first_seen_at":"2026-11-09T22:53:17+00:00","triaged_at":"2026-11-09T22:56:32+00:00","updated_at":"2026-11-09T22:56:32+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T22:56:32Z","model":"claude-haiku-5-5","output":{"fix":"- Hono: move to `4.13.16`\n- Workaround from the advisory: reject an empty object in the validator callback, or validate the result of `await c.req.parseBody()` in the handler","reach":"internet","title":"Hono: form validator skips multipart requests with extra Content-Type parameters","impact":"medium","summary":"Hono's validator('form') middleware only recognizes a multipart/form-data Content-Type with a single boundary parameter, so a request adding a charset parameter or extra whitespace is treated as having no form data. The validation callback then receives an empty object while the handler can still read all submitted fields.","audience":"developers","category":"package","nicknames":[],"who_cares":["hono","node","bun","deno","cloudflare-workers"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"form validation rules bypassed, disallowed fields reach the handler","analyst_note":"","how_to_check":"- Run `npm ls hono` in the project and look for a version between `4.5.1` and `4.13.15`\n- Search the code for `validator('form'` to find routes that rely on the form validator\n- Check whether the validation callback would accept an empty object","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["no-validator-form","urlencoded-only","rejects-empty-object"],"who_is_affected":"Applications that use Hono's validator('form') on routes that accept multipart/form-data and whose validation callback accepts an empty object. An attacker can add a legal Content-Type parameter such as charset to bypass field checks, and the handler still reads the form fields. Routes that do not use validator('form'), use only urlencoded bodies, or reject empty objects are not exposed.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000821,"input_tokens":5086,"output_tokens":625,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-20':27B '4h7h':13A,18A '7m2v':15A,20A 'accept':199C,324C 'add':52B,273C 'affect':223C,311C 'allow':288C 'allow-list':287C 'anoth':104C 'applic':237C,302C,312C 'application/x-www-form-urlencoded':220C 'aris':234C 'await':343C 'bodi':135C,147C,186C 'boundari':47B,99C,173C 'branch':227C 'bun':22B 'c.req.formdata':219C 'c.req.parsebody':131C,217C,344C 'callback':68B,124C,195C,198C,250C,323C,337C 'carri':94C 'charset':54B,109C 'check':141C,176C,294C 'client':261C 'cloudflar':24B 'cloudflare-work':23B 'content':42B,91C,161C,280C 'content-typ':41B,90C,160C,279C 'cwe':26B 'data':65B 'decid':143C 'deno':28B 'detail':139C 'empti':72B,128C,190C,201C,256C,326C,331C 'exact':171C 'extra':9A,57B,112C 'fail':174C,179C,253C 'field':82B,215C,246C,265C,293C,300C 'form':2A,35B,64B,85C,121C,138C,150C,241C,264C,268C,316C,336C 'ghsa':12A,17A 'ghsa-4h7h-rv7c-7m2v':11A,16A 'handler':76B,208C,308C,347C 'header':282C 'hono':21A,29B,32B 'impact':258C 'intend':303C 'issu':233C,310C 'lead':285C 'legal':105C,275C 'like':172C 'list':166C,289C 'look':170C 'may':284C 'middlewar':36B,181C 'multipart/form-data':6A,40B,89C,226C,318C 'never':270C 'node':30B 'noth':95C 'object':73B,129C,191C,202C,257C,327C,332C 'packag':31B 'paramet':10A,48B,55B,100C,106C,165C,276C 'pars':133C 'pass':188C 'pattern':156C,231C 'proceed':205C 'reach':306C 'read':79B,184C,212C 'receiv':70B,126C 'recogn':38B,87C,118C 'reject':243C,305C,329C 'reli':238C 'request':7A,51B,102C,146C,204C,319C 'requir':292C 'required-field':291C 'restrict':245C 'result':341C 'rv7c':14A,19A 'see':271C 'send':263C 'singl':46B,98C 'skip':3A,299C 'still':78B,132C,211C 'strict':155C,230C 'submit':81B,214C 'summari':83C 'treat':60B 'type':43B,92C,162C,281C 'unauthent':260C 'use':314C 'valid':1A,4A,34B,67B,84C,123C,194C,240C,249C,269C,297C,315C,322C,335C,339C 'valu':163C 'whether':144C 'whitespac':58B,113C 'whole':159C 'whose':321C 'workaround':328C 'worker':25B 'written':152C","nicknames":[],"mitigations":[],"who_affected":"Applications that use Hono's validator('form') on routes that accept multipart/form-data and whose validation callback accepts an empty object. An attacker can add a legal Content-Type parameter such as charset to bypass field checks, and the handler still reads the form fields. Routes that do not use validator('form'), use only urlencoded bodies, or reject empty objects are not exposed.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["hono"],"ptokens":["hono"],"labels":["bun","cloudflareworkers","cwe20","deno","hono","medium","node","npm","package"],"campaign_type":null,"search_a":"'4h7h':13A,18A '7m2v':15A,20A 'extra':9A 'form':2A 'ghsa':12A,17A 'ghsa-4h7h-rv7c-7m2v':11A,16A 'hono':21A 'multipart/form-data':6A 'paramet':10A 'request':7A 'rv7c':14A,19A 'skip':3A 'valid':1A,4A","search_b":"'-20':27B 'add':52B 'boundari':47B 'bun':22B 'callback':68B 'charset':54B 'cloudflar':24B 'cloudflare-work':23B 'content':42B 'content-typ':41B 'cwe':26B 'data':65B 'deno':28B 'empti':72B 'extra':57B 'field':82B 'form':35B,64B 'handler':76B 'hono':29B,32B 'middlewar':36B 'multipart/form-data':40B 'node':30B 'object':73B 'packag':31B 'paramet':48B,55B 'read':79B 'receiv':70B 'recogn':38B 'request':51B 'singl':46B 'still':78B 'submit':81B 'treat':60B 'type':43B 'valid':34B,67B 'whitespac':58B 'worker':25B","search_c":"'accept':199C,324C 'add':273C 'affect':223C,311C 'allow':288C 'allow-list':287C 'anoth':104C 'applic':237C,302C,312C 'application/x-www-form-urlencoded':220C 'aris':234C 'await':343C 'bodi':135C,147C,186C 'boundari':99C,173C 'branch':227C 'c.req.formdata':219C 'c.req.parsebody':131C,217C,344C 'callback':124C,195C,198C,250C,323C,337C 'carri':94C 'charset':109C 'check':141C,176C,294C 'client':261C 'content':91C,161C,280C 'content-typ':90C,160C,279C 'decid':143C 'detail':139C 'empti':128C,190C,201C,256C,326C,331C 'exact':171C 'extra':112C 'fail':174C,179C,253C 'field':215C,246C,265C,293C,300C 'form':85C,121C,138C,150C,241C,264C,268C,316C,336C 'handler':208C,308C,347C 'header':282C 'impact':258C 'intend':303C 'issu':233C,310C 'lead':285C 'legal':105C,275C 'like':172C 'list':166C,289C 'look':170C 'may':284C 'middlewar':181C 'multipart/form-data':89C,226C,318C 'never':270C 'noth':95C 'object':129C,191C,202C,257C,327C,332C 'paramet':100C,106C,165C,276C 'pars':133C 'pass':188C 'pattern':156C,231C 'proceed':205C 'reach':306C 'read':184C,212C 'receiv':126C 'recogn':87C,118C 'reject':243C,305C,329C 'reli':238C 'request':102C,146C,204C,319C 'requir':292C 'required-field':291C 'restrict':245C 'result':341C 'see':271C 'send':263C 'singl':98C 'skip':299C 'still':132C,211C 'strict':155C,230C 'submit':214C 'summari':83C 'type':92C,162C,281C 'unauthent':260C 'use':314C 'valid':84C,123C,194C,240C,249C,269C,297C,315C,322C,335C,339C 'valu':163C 'whether':144C 'whitespac':113C 'whole':159C 'whose':321C 'workaround':328C 'written':152C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-01T02:36:54+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-4h7h-rv7c-7m2v","url":"https://github.com/honojs/hono/security/advisories/GHSA-4h7h-rv7c-7m2v","severity":"medium","published_at":"2026-11-01T02:36:54+00:00","modified_at":"2026-11-01T02:36:54+00:00","first_seen_at":"2026-11-09T22:53:17+00:00","fetched_at":"2026-11-09T22:53:17+00:00","note":null}],"documents":[{"id":110464,"url":"https://github.com/honojs/hono/security/advisories/GHSA-4h7h-rv7c-7m2v","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"}