{"id":"CVE-2026-100347","kind":"vulnerability","aliases":["CVE-2026-100347","GHSA-fh4f-47mf-f2gj","GO-2026-6783"],"related":[],"title":"kin-openapi: Unauthenticated panic (DoS) in openapi3filter legacy router via non-canonical/unsupported HTTP method on a static path","description":"## Summary\nThe `openapi3filter.ValidationHandler` (the exported, documented request-validation middleware) hard-wires the legacy router (`routers/legacy`). That router matches the incoming request method verbatim against a trie built exclusively from upper-cased canonical HTTP methods. A request carrying a method token that is not one of the 9 standard methods — a legitimate-but-unsupported token such as `PROPFIND`, or a non-canonical case variant such as lowercase `get` — misses the trie, leaves `route == nil`, and for an existing **static** path falls through to `PathItem.GetOperation(method)`, whose `default:` case calls `panic(...)`. The panic fires inside route resolution, **before any authentication** runs. This is an unauthenticated, remotely triggerable denial of service (recovered per-connection panic + unbounded error-log growth).\n\n## Root Cause\n- `openapi3filter/validation_handler.go:39` — `ValidationHandler.Load()` always constructs `legacyrouter.NewRouter(doc)`; there is no alternative router option on this path.\n- `routers/legacy/router.go:109` — the request method is used verbatim (`method, url := req.Method, ...`); there is no canonicalization or rejection of unknown method tokens.\n- `routers/legacy/router.go:69-70` — the trie is populated with `strings.ToUpper(method)` keys taken from `pathItem.Operations()` (canonical `http.Method*` constants only).\n- `routers/legacy/router.go:141` — `root.Match(method + \" \" + remainingPath)` misses for a non-canonical/unsupported method → `route == nil`.\n- `routers/legacy/router.go:146-150` — in the `route == nil` block, `doc.Paths.Value(path)` returns non-nil for an existing static path, and control reaches `pathItem.GetOperation(method)`.\n- `openapi3/path_item.go:174` — `GetOperation`'s `switch method` has no matching case → `default: panic(fmt.Errorf(\"unsupported HTTP method %q\", method))`.\n\n## Impact\nAn unauthenticated attacker sends a single request with a non-standard HTTP method token to any existing static path. The handler goroutine panics; Go's `net/http` recovers the panic per connection (process survives), aborts the connection (client sees a reset / 500), and logs a full stack trace. Repeated requests cause connection churn and unbounded `http: panic serving` log growth, and the request never reaches authentication. Availability impact (A:L) under the default synchronous `ValidationHandler` middleware; on non-net/http hosts or when reached on an application goroutine the ceiling is a full crash.\n\n## Proof of Concept\nServe any spec with a static path (e.g. `/ping`) behind `openapi3filter.ValidationHandler`, then:\n```\nprintf 'PROPFIND /ping HTTP/1.1\\r\\nHost: x\\r\\n\\r\\n' | nc target 8080   # connection aborted (panic)\nprintf 'get /ping HTTP/1.1\\r\\nHost: x\\r\\n\\r\\n'      | nc target 8080   # connection aborted (panic)\nprintf 'GET /ping HTTP/1.1\\r\\nHost: x\\r\\n\\r\\n'      | nc target 8080   # 200 OK (process survived)\n```\nReproduced end-to-end against a real `net/http.Server` + `ValidationHandler`: `PROPFIND /ping` and lowercase `get /ping` both abort the connection with a panic at `path_item.go:174` (stack: `GetOperation` <- `legacy.FindRoute` router.go:150 <- `ValidationHandler.validateRequest` validation_handler.go:84); the process stays alive and subsequent `GET /ping` returns 200.\n\n## Attack Chain\n1. Entry: unauthenticated `PROPFIND /ping HTTP/1.1` (any known static path). Guard: net/http method validation. Bypass proof: net/http accepts any valid HTTP token as a method — `PROPFIND` and lowercase `get` both reach the handler.\n2. Route match: `legacy/router.go:141` `root.Match(\"PROPFIND /ping\")`. Guard: trie match. Bypass proof: trie holds only upper-cased canonical methods → miss → `route == nil`.\n3. `route == nil` block: `router.go:146` `doc.Paths.Value(\"/ping\")` → non-nil for an existing static path (exact map lookup). Guard: `pathItem == nil` check (l.147). Bypass proof: static path exists → not nil → proceeds.\n4. Sink: `router.go:150` `pathItem.GetOperation(\"PROPFIND\")` → `path_item.go:174` `default: panic(...)`.\n5. Impact: handler goroutine panics; net/http recovers per connection; request never reaches auth.\n\n## Bypass Evidence\n- net/http does NOT reject non-standard method tokens — confirmed empirically: `PROPFIND` and lowercase `get` both reached the handler and panicked.\n- No canonicalization/rejection exists between `FindRoute` entry and `GetOperation`; `req.Method` is used verbatim (router.go:109).\n- `git show v0.144.0:openapi3/path_item.go` shows `panic(...)` at line 174; `git show v0.144.0:routers/legacy/router.go` shows verbatim method use and the unguarded `GetOperation` call. `git log v0.144.0..HEAD` on these files is empty (no post-tag fix).\n\n## Scoping Note\nThe panic requires the request path to be an exact static (non-templated) key in the served spec. A concrete path against a `/{id}` template returns a clean 500 (not a panic), because `Paths.Value` is an exact map lookup. Static paths (`/health`, `/login`, `/version`, `/metrics`, `/ping`, `/`) are ubiquitous in real specs and discoverable from public specs/standard endpoints, so a vulnerable target almost always exists. This makes the finding arguably broader than existing panic advisories, as it needs no special spec construct — any static path suffices.\n\n## Affected Versions\n`<= 0.144.0` (present on the latest release tag v0.144.0; long-standing; no patched version).\n\n## Suggested Fix\nIn the legacy router, canonicalize/validate the request method before route resolution and return `ErrMethodNotAllowed`/`ErrPathNotFound` for unknown methods, or make `PathItem.GetOperation` return an error (nil) for unrecognized methods instead of calling `panic`.\n\n---\nReported by **zx (Jace)** — GitHub: @manus-use","summary":"The openapi3filter legacy router in the Go library kin-openapi panics when it receives a non-canonical or unsupported HTTP method on a static path. An unauthenticated remote request can therefore crash any service that uses this router, causing denial of service.","severity":"high","cvss":5.3,"epss":0.00515,"exploited":false,"exploited_at":null,"products":[{"name":"github.com/getkin/kin-openapi","fixed":["0.145.0"],"affected":"< 0.145.0","ecosystem":"go"},{"name":"github.com/getkin/kin-openapi","fixed":["0.145.0"],"affected":"<= 0.144.0","ecosystem":"go"}],"ecosystems":["go"],"tags":["api-server","cwe-20","cwe-248","go","kin-openapi","openapi","package"],"not_affected_if":["no-http-router","offline-spec-parsing"],"how_to_check":"- Check whether the module `github.com/getkin/kin-openapi` is in `go.mod` and which version is pinned\n- Run `go list -m github.com/getkin/kin-openapi` to see the resolved version\n- Check whether the code uses the openapi3filter legacy router to validate incoming requests","fix":"- `github.com/getkin/kin-openapi` `0.145.0`","status":"open","published_at":"2026-10-15T16:17:30+00:00","first_seen_at":"2026-11-06T00:09:04+00:00","triaged_at":"2026-11-06T00:10:34+00:00","updated_at":"2026-11-06T00:19:08+00:00","category":"package","confidence":0.6,"triage":{"at":"2026-11-06T00:10:34Z","model":"claude-haiku-5-5","output":{"fix":"- `github.com/getkin/kin-openapi` `0.145.0`","reach":"internet","title":"kin-openapi: unauthenticated request with odd HTTP method crashes Go service","impact":"low","summary":"The openapi3filter legacy router in the Go library kin-openapi panics when it receives a non-canonical or unsupported HTTP method on a static path. An unauthenticated remote request can therefore crash any service that uses this router, causing denial of service.","audience":"developers","category":"package","nicknames":[],"who_cares":["go","kin-openapi","openapi","api-server"],"confidence":0.6,"fix_status":"available","needs_auth":"no","worst_case":"unauthenticated remote request crashes the service process","analyst_note":"","how_to_check":"- Check whether the module `github.com/getkin/kin-openapi` is in `go.mod` and which version is pinned\n- Run `go list -m github.com/getkin/kin-openapi` to see the resolved version\n- Check whether the code uses the openapi3filter legacy router to validate incoming requests","plain_action":"","needs_analyst":false,"not_affected_if":["no-http-router","offline-spec-parsing"],"who_is_affected":"Services written in Go that import kin-openapi and use the openapi3filter legacy router to route or validate incoming HTTP requests on static paths are exposed. Projects that only use kin-openapi for offline spec parsing or code generation, and do not serve requests through that router, can skip it.","user_interaction":"no","needs_special_setup":"unknown","severity_if_unknown":"high"},"cost_usd":0.000702,"input_tokens":4271,"output_tokens":549,"severity_before":"unknown"},"analyst_status":null,"analyst_note":null,"search":"'-100347':24A,35A '-150':296C '-20':46B '-2026':23A,31A,34A '-248':48B '-6783':32A '-70':263C '/getkin/kin-openapi':38A,41A '/http':417C '/ping':443C,449C,466C,483C,510C,514C,537C,546C,582C,605C '/unsupported':15A,290C '1':542C '109':241C '141':280C,579C '146':295C '174':319C '2':575C '200':495C,539C '3':599C '39':225C '4':630C '47mf':28A '500':378C '69':262C '8080':460C,477C,494C '9':148C 'abort':371C,462C,479C,516C 'accept':559C 'aliv':533C 'altern':234C 'alway':227C 'api':43B 'api-serv':42B 'applic':424C 'attack':339C,540C 'authent':201C,402C 'avail':403C 'behind':444C 'block':301C,602C 'built':127C 'bypass':556C,586C,622C 'call':191C 'canon':14A,73B,133C,164C,275C,289C,594C 'canonic':254C 'carri':138C 'case':132C,165C,190C,327C,593C 'caus':95B,223C,387C 'ceil':427C 'chain':541C 'check':620C 'churn':389C 'client':374C 'concept':434C 'connect':215C,368C,373C,388C,461C,478C,518C 'constant':277C 'construct':228C 'control':314C 'crash':88B,431C 'cve':22A,33A 'cwe':45B,47B 'default':189C,328C,409C 'denial':96B,209C 'doc':230C 'doc.paths.value':302C,604C 'document':104C 'dos':6A 'e.g':442C 'end':501C,503C 'end-to-end':500C 'entri':543C 'error':219C 'error-log':218C 'exact':614C 'exclus':128C 'exist':180C,310C,354C,611C,626C 'export':103C 'f2gj':29A 'fall':183C 'fh4f':27A 'fire':195C 'fmt.errorf':330C 'full':382C,430C 'get':170C,465C,482C,513C,536C,570C 'getoper':320C,525C 'ghsa':26A 'ghsa-fh4f-47mf-f2gj':25A 'github.com':37A,40A 'github.com/getkin/kin-openapi':36A,39A 'go':30A,49B,61B,361C 'goroutin':359C,425C 'growth':221C,396C 'guard':552C,583C,617C 'handler':358C,574C 'hard':110C 'hard-wir':109C 'hold':589C 'host':418C 'http':16A,76B,134C,332C,349C,392C,562C 'http.method':276C 'http/1.1':450C,467C,484C,547C 'impact':336C,404C 'incom':120C 'insid':196C 'key':271C 'kin':2A,51B,64B 'kin-openapi':1A,50B,63B 'known':549C 'l':406C 'l.147':621C 'leav':174C 'legaci':9A,57B,113C 'legacy.findroute':526C 'legacy/router.go':578C 'legacyrouter.newrouter':229C 'legitim':153C 'legitimate-but-unsupport':152C 'librari':62B 'log':220C,380C,395C 'lookup':616C 'lowercas':169C,512C,569C 'map':615C 'match':118C,326C,577C,585C 'method':17A,77B,122C,135C,140C,150C,187C,244C,248C,259C,270C,282C,291C,317C,323C,333C,335C,350C,554C,566C,595C 'middlewar':108C,412C 'miss':171C,284C,596C 'n':455C,457C,472C,474C,489C,491C 'nc':458C,475C,492C 'net':416C 'net/http':363C,553C,558C 'net/http.server':507C 'never':400C 'nhost':452C,469C,486C 'nil':176C,293C,300C,307C,598C,601C,608C,619C,628C 'non':13A,72B,163C,288C,306C,347C,415C,607C 'non-canon':12A,71B,162C,287C 'non-net':414C 'non-nil':305C,606C 'non-standard':346C 'ok':496C 'one':145C 'openapi':3A,52B,53B,65B 'openapi3/path_item.go':318C 'openapi3filter':8A,56B 'openapi3filter.validationhandler':101C,445C 'openapi3filter/validation_handler.go':224C 'option':236C 'packag':54B 'panic':5A,66B,192C,194C,216C,329C,360C,366C,393C,463C,480C,521C 'path':21A,81B,182C,239C,303C,312C,356C,441C,551C,613C,625C 'path_item.go:174':523C 'pathitem':618C 'pathitem.getoperation':186C,316C,633C 'pathitem.operations':274C 'per':214C,367C 'per-connect':213C 'popul':267C 'printf':447C,464C,481C 'pro':634C 'proceed':629C 'process':369C,497C,531C 'proof':432C,557C,587C,623C 'propfind':159C,448C,509C,545C,567C,581C 'q':334C 'r':451C,454C,456C,468C,471C,473C,485C,488C,490C 'reach':315C,401C,421C,572C 'real':506C 'receiv':69B 'recov':212C,364C 'reject':256C 'remainingpath':283C 'remot':84B,207C 'repeat':385C 'reproduc':499C 'req.method':250C 'request':85B,106C,121C,137C,243C,343C,386C,399C 'request-valid':105C 'reset':377C 'resolut':198C 'return':304C,538C 'root':222C 'root.match':281C,580C 'rout':175C,197C,292C,299C,576C,597C,600C 'router':10A,58B,94B,114C,117C,235C 'router.go:146':603C 'router.go:150':527C,632C 'routers/legacy':115C 'routers/legacy/router.go':240C,261C,279C,294C 'run':202C 'see':375C 'send':340C 'serv':394C,435C 'server':44B 'servic':90B,98B,211C 'singl':342C 'sink':631C 'spec':437C 'stack':383C,524C 'standard':149C,348C 'static':20A,80B,181C,311C,355C,440C,550C,612C,624C 'stay':532C 'strings.toupper':269C 'subsequ':535C 'summari':99C 'surviv':370C,498C 'switch':322C 'synchron':410C 'taken':272C 'target':459C,476C,493C 'therefor':87B 'token':141C,156C,260C,351C,563C 'trace':384C 'trie':126C,173C,265C,584C,588C 'trigger':208C 'unauthent':4A,83B,206C,338C,544C 'unbound':217C,391C 'unknown':258C 'unsupport':75B,155C,331C 'upper':131C,592C 'upper-cas':130C,591C 'url':249C 'use':92B,246C 'valid':107C,555C,561C 'validation_handler.go:84':529C 'validationhandl':411C,508C 'validationhandler.load':226C 'validationhandler.validaterequest':528C 'variant':166C 'verbatim':123C,247C 'via':11A 'whose':188C 'wire':111C 'x':453C,470C,487C","nicknames":[],"mitigations":[],"who_affected":"Services written in Go that import kin-openapi and use the openapi3filter legacy router to route or validate incoming HTTP requests on static paths are exposed. Projects that only use kin-openapi for offline spec parsing or code generation, and do not serve requests through that router, can skip it.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["githubcomgetkinkinopenapi"],"ptokens":["com","getkin","github","kin","openapi"],"labels":["apiserver","cwe20","cwe248","go","high","kinopenapi","openapi","package"],"campaign_type":null,"first_public_at":"2026-07-25T12:58:54+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"govuln","external_id":"GO-2026-6783","url":"https://pkg.go.dev/vuln/GO-2026-6783","severity":null,"published_at":"2026-11-05T22:53:53+00:00","modified_at":"2026-11-05T22:53:53+00:00","first_seen_at":"2026-11-06T00:09:04+00:00","fetched_at":"2026-11-06T00:09:04+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-100347","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-100347","severity":null,"published_at":"2026-10-15T16:17:30+00:00","modified_at":"2026-10-15T17:17:07+00:00","first_seen_at":"2026-11-06T00:19:01+00:00","fetched_at":"2026-11-06T00:19:01+00:00","note":null},{"source":"ghsa","external_id":"GHSA-fh4f-47mf-f2gj","url":"https://github.com/advisories/GHSA-fh4f-47mf-f2gj","severity":"medium","published_at":"2026-10-15T20:15:48+00:00","modified_at":"2026-10-15T20:15:50+00:00","first_seen_at":"2026-11-06T00:19:08+00:00","fetched_at":"2026-11-06T00:19:08+00:00","note":null}],"documents":[{"id":81812,"url":"https://github.com/getkin/kin-openapi/commit/f1a5b523b82868d2d9be2e116b4e942892be72c3","title":"Patch: github.com","kind":"other","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":81804,"url":"https://github.com/getkin/kin-openapi/releases/tag/v0.145.0","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":81814,"url":"https://github.com/getkin/kin-openapi/security/advisories/GHSA-fh4f-47mf-f2gj","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":"2026-07-25T12:58:54+00:00","relation":"advisory","confidence":null,"note":"Vendor advisory: github.com"},{"id":81938,"url":"https://api.github.com/repos/getkin/kin-openapi/security-advisories/GHSA-fh4f-47mf-f2gj","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"}],"exploit_sources":[{"type":"epss","score":0.00515,"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-100347"}],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}