---
id: "CVE-2026-100351"
page: "https://infrastack.ai/live/CVE-2026-100351"
kind: "vulnerability"
aliases: ["CVE-2026-100351", "GHSA-23vg-4cjm-66q5", "GO-2026-6769"]
title: "kin-openapi: ValidationHandler security-requirement bypass via encoded-path operation confusion"
severity: "high"
cvss: 7.4
epss: 0.00488
exploited: false
status: "open"
category: "package"
products: [{"name": "github.com/getkin/kin-openapi", "fixed": ["0.147.0"], "affected": ">= 0.144.0, < 0.147.0", "ecosystem": "go"}]
ecosystems: ["go"]
tags: ["api-servers", "cwe-289", "cwe-436", "go", "kin-openapi", "openapi", "package"]
not_affected_if: ["auth-enforced-elsewhere", "not-using-validationhandler"]
published_at: "2026-10-15T16:17:31+00:00"
first_seen_at: "2026-11-06T00:09:04+00:00"
updated_at: "2026-11-06T00:19:08+00:00"
sources: [{"source": "govuln", "url": "https://pkg.go.dev/vuln/GO-2026-6769", "first_seen_at": "2026-11-06T00:09:04+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-100351", "first_seen_at": "2026-11-06T00:19:01+00:00"}, {"source": "ghsa", "url": "https://github.com/advisories/GHSA-23vg-4cjm-66q5", "first_seen_at": "2026-11-06T00:19:08+00:00"}]
exploit_sources: [{"type": "epss", "score": 0.00488, "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-100351"}]
---

# kin-openapi: ValidationHandler security-requirement bypass via encoded-path operation confusion

Link for people: https://infrastack.ai/live/CVE-2026-100351 (this .md is for agents)

A flaw in the Go library kin-openapi lets a request with an encoded path be matched to the wrong operation in ValidationHandler, so the security requirement for that operation is bypassed. An attacker can reach an endpoint that should have required authentication or authorization.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- go:github.com/getkin/kin-openapi affected >= 0.144.0, < 0.147.0 fixed 0.147.0

## How to check

- Find the version of github.com/getkin/kin-openapi in go.mod, for example with `go list -m github.com/getkin/kin-openapi`
- Check whether the application uses ValidationHandler from this library to enforce OpenAPI security requirements

## Fix

- github.com/getkin/kin-openapi: `0.147.0`

## Timeline

- 2026-11-06T00:09:04+00:00 govuln https://pkg.go.dev/vuln/GO-2026-6769
- 2026-11-06T00:19:01+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-100351
- 2026-11-06T00:19:08+00:00 ghsa https://github.com/advisories/GHSA-23vg-4cjm-66q5

## Documents

- [advisory] Vendor advisory: github.com https://github.com/getkin/kin-openapi/security/advisories/GHSA-23vg-4cjm-66q5
- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/getkin/kin-openapi/security-advisories/GHSA-23vg-4cjm-66q5
- [fix] Patch: github.com https://github.com/getkin/kin-openapi/commit/eda80e2676e9f577ceed2dd80e64f16083edb041
- [fix] Release notes: github.com https://github.com/getkin/kin-openapi/releases/tag/v0.147.0

## From the sources

## Summary

`openapi3filter.ValidationHandler.Middleware` validates requests with kin-openapi's
legacy router, which selects an OpenAPI operation from the decoded `URL.Path`. The
method is documented as implementing `gorilla/mux.MiddlewareFunc`, but a downstream
gorilla/mux router configured with `UseEncodedPath()` selects its handler from the
encoded representation (`URL.RawPath`).

An unauthenticated request such as `/public%2Fstatus` can therefore be validated as an
intentionally public operation (`/public/status`) and then dispatched to a protected
operation (`/{id}`). The configured, rejecting `AuthenticationFunc` is never invoked,
and the protected downstream handler runs.

This is distinct from GHSA-r277-6w6q-xmqw. The behavior below uses an explicit
authentication callback that rejects missing credentials and remains reproducible
after the v0.144.0 fix for the unsafe default callback.

## Affected products

- Product: `github.com/getkin/kin-openapi`
- Component: `openapi3filter.ValidationHandler.Middleware`
- Confirmed post-GHSA affected releases: v0.144.0, v0.145.0, and v0.146.0
- Reporter attestation: each listed release was checked out separately, the attached
  single-file test was copied into `openapi3filter/`, and that test passed; maintainers
  should independently confirm the version range
- Confirmed affected development revision: `d33e44e67734dcde81b576582185e1343fb3985d`
- v0.143.0 also reproduces this mechanism, but GHSA-r277-6w6q-xmqw already provides a
  simpler bypass on that release; the distinct post-fix claim starts at v0.144.0
- Earlier releases: not tested; please treat the introduction boundary as unknown

## Security impact

An unauthenticated remote requester can reach a handler whose OpenAPI operation
requires authentication when all of the following are true:

1. the application uses `ValidationHandler.Middleware` as the security gate;
2. the downstream router preserves and interprets an encoded path, such as
   gorilla/mux with `UseEncodedPath()`;
3. a public exact route and a protected parameterized route overlap after decoding;
4. the public and protected operations expose the same HTTP method;
5. the protected handler relies on the validation layer's security decision.

The protected operation's path-parameter value is constrained: it is an encoded
representation that decodes to a public literal path (`public%2Fstatus` in this PoC),
not an arbitrary attacker-selected identifier. A protected operation without a
compatible parameterized path is not reachable through this specific mechanism.

- Primitive: the security decision is made for a different OpenAPI operation than the
  operation dispatched by the application router.
- Demonstrated impact: a protected handler executes while the explicitly rejecting
  `AuthenticationFunc` is never invoked.
- Impact ceiling: confidentiality or integrity loss when the reachable protected
  handler has that authority; the PoC does not demonstrate data disclosure or state
  modification.
- Availability impact: not demonstrated.

## Root cause

At the confirmed development revision:

- `openapi3filter/validation_handler.go`: `ValidationHandler.Load` constructs
  `routers/legacy.NewRouter` unconditionally.
- `routers/legacy/router.go`: route selection uses the decoded request path.
- `routers/gorillamux/router.go`: the kin-openapi gorilla router constructs a
  gorilla/mux router with `UseEncodedPath()`.
- `ValidationHandler.Middleware` forwards the unchanged request after validation.

The component making the authentication decision and the component dispatching the
handler can therefore disagree about the selected operation.

## Reproduction

The attached PoC uses a real `net/http` server, an explicit API-key callback that
rejects missing credentials, and a downstream gorilla/mux router with
`UseEncodedPath()`.

From a kin-openapi checkout, copy the self-contained attachment
`encoded_path_route_confusion_test.go.txt` into `openapi3filter/` as
`encoded_path_route_confusion_test.go`, then run:

```sh
go test -v ./openapi3filter -run '^TestEncodedPathAuthorizationBypass$' -count=1
```

Expected attack observation:

```text
status=202 downstream_route=/{id} protected_id=public%2Fstatus authentication_calls=0
wiring=Router.Use status=202 downstream_route=/{id} protected_id=public%2Fstatus authentication_calls=0
```

Controls included in the test show that:

- `/ordinary` selects the protected operation, invokes authentication once, and is
  rejected with HTTP 401;
- `/public/status` reaches only the intentionally public handler;
- the encoded request reaches the protected `/{id}` handler with HTTP 202 while the
  authentication callback remains uncalled;
- both external wrapping and the documented
  `router.Use(validationHandler.Middleware)` wiring reproduce the same result.

## Reverse-proxy reachability

The same request was reproduced through Nginx 1.31.3 using the official
`nginx:alpine` image digest
`sha256:4a73073bd557c65b759505da037898b61f1be6cbcc3c2c3aeac22d2a470c1752`.

The exact container invocation was:

```sh
docker run --rm --name kin-openapi-nginx \
  --add-host=host.docker.internal:host-gateway \
  -p 18081:8080 -p 18082:8081 \
  -v "$PWD/poc/nginx.conf:/etc/nginx/nginx.conf:ro" \
  nginx:alpine
```

Container port 8080 uses `proxy_pass http://host.docker.internal:18080;` without a
replacement URI. Host port 18081 therefore preserved `/public%2Fstatus`; the protected
handler returned HTTP 202 and the
authentication callback remained at zero calls. With
`proxy_pass http://host.docker.internal:18080/;` on container port 8081 / host port
18082, Nginx canonicalized the upstream URI; both layers selected `/public/status` and
the bypass did not occur.

Nginx access-log observations:

```text
server_port=8080 "GET /public%2Fstatus HTTP/1.1" 202 0 "curl/8.7.1"
server_port=8081 "GET /public%2Fstatus HTTP/1.1" 204 0 "curl/8.7.1"
server_port=8080 "GET /ordinary HTTP/1.1" 401 0 "curl/8.7.1"
```

The response route headers were `X-Poc-Route: /{id}` on the preserving listener and
`X-Poc-Route: /public/status` on the canonicalizing listener. Backend observations for
the two requests were:

```text
request_uri="/public%2Fstatus" path="/public/status" raw_path="/public%2Fstatus" auth_before=0
completed request_uri="/public%2Fstatus" auth_after=0
request_uri="/public/status" path="/public/status" raw_path="" auth_before=0
completed request_uri="/public/status" auth_after=0
```

This control shows that upstream path handling is a deployment precondition rather
than claiming that every proxy configuration is affected.

The canonical protected control produced:

```text
request_uri="/ordinary" path="/ordinary" raw_path="" auth_before=0
completed request_uri="/ordinary" auth_after=1
```

## Suggested remediation

The authentication layer and downstream dispatcher must select the same OpenAPI
operation from the same request representation.

Potential approaches:

1. make `ValidationHandler` accept a caller-supplied `routers.Router` and require it to
   match downstream routing semantics;
2. document that `NewValidator` already accepts a router but is safe only when the
   supplied router selects operations using the same semantics as the dispatcher;
   callers must also supply an `AuthenticationFunc` through `ValidationOptions`, or
   protected requests fail with the existing missing-authentication-service error;
3. as an interim hardening option, make `ValidationHandler` fail closed on an encoded
   path separator when `URL.Path` and `URL.RawPath` can select different operations,
   and verify this behavior against the full suite;
4. document the route-identity requirement and add encoded-separator regression tests.

Replacing the legacy router with the kin-openapi gorilla router closes this PoC, but a
local compatibility check changed two existing missing-path-parameter tests from HTTP
400 semantics to route-not-found HTTP 404 semantics. A direct router swap is therefore
not a fully valida

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
