Skip to content

fix: trim Options.Prefix in place so the request body survives security validation - #17

Merged
mromaszewicz merged 3 commits into
oapi-codegen:mainfrom
blacksud0:fix-prefix-body-drain
Oct 23, 2026
Merged

mromaszewicz merged 3 commits into
oapi-codegen:mainfrom
blacksud0:fix-prefix-body-drain

Conversation

@blacksud0

Copy link
Copy Markdown
Contributor

Fixes #16.

Request.Clone copies the Body reference. With Options.Prefix set and a security scheme in the spec, openapi3filter's security validation reads the body from the live request and restores a fresh reader onto the clone only — so every POST/PUT/PATCH through a prefixed mount reached its handler with a drained, zero-byte body (even with ExcludeRequestBody enabled, since the read belongs to the security path).

This trims URL.Path — and RawPath, which the clone approach left untrimmed — in place, restoring both in a defer. RequestValidationInput.Request stays the live request, so the body restore lands where it is needed; the restore runs before next, so handlers still observe the original path and the existing prefix test's path assertion keeps passing.

The new regression test fails against the previous clone-based handling (the handler received a drained body … was []) and passes with this change. Full suite green. This is the fix we have been running in production as a vendored copy.

…ty validation

Request.Clone copies the Body reference. With Prefix set and a security
scheme in the spec, openapi3filter's security validation reads the body
from the live request and restores a fresh reader onto the clone only, so
every POST/PUT/PATCH through a prefixed mount reached its handler with a
drained, zero-byte body — even with ExcludeRequestBody enabled, since the
read belongs to the security path.

Trimming URL.Path (and RawPath, which the clone approach left untrimmed)
in place with a deferred restore keeps RequestValidationInput.Request the
live request, so the body restore lands where it is needed, and the
restore runs before next so handlers still observe the original path —
the existing prefix test's path assertion keeps passing.

The new regression test fails against the previous clone-based handling
and passes with this change.

Fixes oapi-codegen#16
@mromaszewicz mromaszewicz added the bug Something isn't working label Oct 23, 2026
mromaszewicz and others added 2 commits October 22, 2026 18:09
Bring in main so the fix builds and is tested against kin-openapi
v0.152.0 (with Options.KeepValidatedValue) and echo v5.4.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the prefix body regression test into oapi_validate_test.go next to
TestOapiRequestValidatorWithPrefix and broaden it: the handler must get
the exact body bytes and the original /api path for plain body
validation, for security validation with ExcludeRequestBody, and with
KeepValidatedValue, where the body must also expose ValidatedValue().
A new test sends a %2F path parameter under the prefix, which only
routes when the prefix is trimmed from URL.RawPath too.

All of these fail against the previous req.Clone()-based handling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mromaszewicz

Copy link
Copy Markdown
Member

Thanks for the fix, @blacksud0! I pushed two commits on top of your branch so this can go in:

  • merged main, so the PR now builds against kin-openapi v0.152.0 and echo v5.4.1
  • moved your regression test into oapi_validate_test.go next to TestOapiRequestValidatorWithPrefix and added a few more cases: exact body bytes and the original /api/... path for plain body validation, security validation with ExcludeRequestBody, and KeepValidatedValue (the handler's body exposes ValidatedValue()), plus a %2F path parameter under the prefix to cover the RawPath trimming

Your commit and the fix in oapi_validate.go are unchanged. All the new cases fail with the old req.Clone() approach and pass with your change.

mromaszewicz added a commit to karlpip/echo-middleware that referenced this pull request Oct 23, 2026
Validating a req.Clone() meant openapi3filter put the re-readable body,
the KeepValidatedValue wrapper and any defaults-rewritten ContentLength
back on the clone only. Copying Body/GetBody back still missed
ContentLength, and only URL.Path was trimmed, so percent-encoded path
parameters under a prefix mis-routed.

Follow the approach of oapi-codegen/echo-v5-middleware#17 by blacksud0
so both repos share one fix: trim URL.Path and URL.RawPath on the live
request and restore them in a defer that runs before the next handler.
Everything kin writes to the body now lands on the request the handler
sees. An AuthenticationFunc reading GetEchoContext(ctx).Request().URL.Path
now sees the trimmed path during validation.

Keep the POST case added to TestOapiRequestValidatorWithPrefix and add
tests for the issue oapi-codegen#49 security + AuthenticationFunc + body scenario
(exact body, ContentLength, original path), a defaults-rewritten body,
KeepValidatedValue, and a percent-encoded path parameter under a prefix.

Closes oapi-codegen#49

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mromaszewicz added a commit to oapi-codegen/echo-middleware that referenced this pull request Oct 23, 2026
* restore body on clone

* add test

* Trim the prefix in place instead of validating a clone

Validating a req.Clone() meant openapi3filter put the re-readable body,
the KeepValidatedValue wrapper and any defaults-rewritten ContentLength
back on the clone only. Copying Body/GetBody back still missed
ContentLength, and only URL.Path was trimmed, so percent-encoded path
parameters under a prefix mis-routed.

Follow the approach of oapi-codegen/echo-v5-middleware#17 by blacksud0
so both repos share one fix: trim URL.Path and URL.RawPath on the live
request and restore them in a defer that runs before the next handler.
Everything kin writes to the body now lands on the request the handler
sees. An AuthenticationFunc reading GetEchoContext(ctx).Request().URL.Path
now sees the trimmed path during validation.

Keep the POST case added to TestOapiRequestValidatorWithPrefix and add
tests for the issue #49 security + AuthenticationFunc + body scenario
(exact body, ContentLength, original path), a defaults-rewritten body,
KeepValidatedValue, and a percent-encoded path parameter under a prefix.

Closes #49

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Marcin Romaszewicz <marcinr@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@mromaszewicz
mromaszewicz merged commit 5ef4185 into oapi-codegen:main Oct 23, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Options.Prefix drains the request body before the handler sees it

2 participants