fix(deps): update module github.com/getkin/kin-openapi to v0.144.0 [security] - #85
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
v0.143.0→v0.144.0kin-openapi: ValidationHandler.Load() Fail-Open Authentication Bypass via NoopAuthenticationFunc Default
GHSA-r277-6w6q-xmqw
More information
Details
Summary
ValidationHandler.Load()ingetkin/kin-openapisilently replaces a nilAuthenticationFuncwithNoopAuthenticationFunc, which always returnsnilwithout performing any credential check. Because this substitution happens unconditionally when the caller omits the field, every OpenAPIsecurityrequirement declared in the spec is silently satisfied for unauthenticated requests. An unauthenticated remote attacker can reach handlers for routes whose OpenAPI operation requires an API key, OAuth token, or any other security scheme if the application relies onValidationHandleras its enforcement middleware.Details
ValidationHandleris an HTTP middleware exported byopenapi3filterthat validates incoming requests and responses against a loaded OpenAPI specification. ItsLoad()method initialises default fields before the handler begins serving:NoopAuthenticationFuncis defined as:It always returns
nil, meaning every security scheme check it handles is automatically approved.When a request arrives,
ServeHTTP→before→validateRequestassembles aRequestValidationInputwith the currentAuthenticationFunc(now the no-op) injected intoOptions:Inside
ValidateRequest, each security requirement callsoptions.AuthenticationFunc:Because
fis the no-op (notnil), theErrAuthenticationServiceMissingguard is never triggered andf(...)returnsnil, clearing the security requirement. Control then proceeds to the protected handler (validation_handler.go:61-62).The critical contradiction is that callers who use
ValidateRequestdirectly with a nilAuthenticationFuncget fail-closed behavior (ErrAuthenticationServiceMissing), while callers who use the higher-levelValidationHandlerwith a nilAuthenticationFuncget fail-open behavior. Since omittingAuthenticationFuncis the natural default, the majority of real-world integrations are vulnerable.Affected source file and line:
openapi3filter/validation_handler.go:47–49(commit30e2923, tagv0.143.0).PoC
Environment
Step 1 — Build the Docker image
From the repository root (parent of
vuln-001/):The
Dockerfilecopies the localkin-openapisource into/kin-openapi/inside the image and builds a Go binary (/poc-binary) frommain.go. Thego.modinside the image uses areplacedirective pointing to/kin-openapi, so no network access to the Go module proxy is required.Step 2 — Run the container
Step 3 (alternative) — Use the Python helper
What the PoC does
main.gocreates a temporary OpenAPI 3.0 spec that declaresGET /secretas protected by anapiKeysecurity scheme:It then constructs a
ValidationHandlerwithout settingAuthenticationFunc, callsLoad(), and sends a request with noX-Api-Keyheader:Expected (vulnerable) output
The contrast block confirms fail-closed behavior when
ValidateRequestis called directly. The exploit block confirms fail-open behavior throughValidationHandler. Status 200 andSECRET_DATAare returned without any credential.Remediation patch
After this change, a nil
AuthenticationFuncpropagates intoValidateRequest, which returnsErrAuthenticationServiceMissingand rejects the request. Callers who genuinely want to skip authentication can still opt in explicitly:h.AuthenticationFunc = openapi3filter.NoopAuthenticationFunc.Impact
This is an authentication bypass vulnerability (CWE-287). Any application that:
openapi3filter.ValidationHandleras its HTTP middleware, andsecurityrequirements in its OpenAPI specification, andAuthenticationFunc,is fully exposed. An unauthenticated remote attacker can send requests to any protected endpoint without supplying credentials; the middleware accepts the request and forwards it to the underlying handler as if authentication had succeeded.
Affected parties include all Go services that adopt
ValidationHandleras a drop-in validation layer and rely on OpenAPIsecuritydeclarations for access control without adding a separate authentication layer upstream (e.g., an API gateway or reverse proxy). Because the insecure behavior is the default, developers following the "getting started" path are affected without any additional mistake.The confidentiality and integrity of data behind secured endpoints are both at high risk. Availability is not directly affected by this vulnerability.
Reproduction artifacts
Dockerfilepoc.pySeverity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
kin-openapi openapi3filter: unauthenticated nil-pointer panic when validating a request against a
contentparameter whose media type has no schemaCVE-2026-73502 / GHSA-jpcw-4wr7-c3vq
More information
Details
github.com/getkin/kin-openapi<= 0.143.0(introduced inv0.2.0, PR #90, 2019-05-07; reproduced onHEAD30e2923)Summary
openapi3filter.ValidateRequestcontains a NULL-pointer-dereference denial of service: any unauthenticated client can crash the request-validation path with a single HTTP request. When an operation declares acontentparameter (as opposed to aschemaparameter) whose media type object has noschema, request validation dereferences that missing schema and panics. The document is legal under the OpenAPI Specification — kin-openapi's owndoc.Validate()accepts it — and the defect affects both OpenAPI 3.0.x and 3.1.x. Depending on how the library is wired into the server (see Impact), this ranges from a per-request abort with unbounded panic-log growth to a full remote process crash.Details
The decoder used for
contentparameters when no customParamDecoderis configured (the library default),defaultContentParameterDecoder, dereferences the media-type schema without a nil check.openapi3filter/req_resp_decoder.go, around line 197:The function guards
param.Content == nil,len(content) != 1, andmt == nil, but nevermt.Schema == nil.Why a schema-less content parameter is legal (so the sink is reachable —
doc.Validate()returns no error), in both 3.0.x and 3.1.x:openapi3/parameter.go—Parameter.Validateonly enforces exactly one ofschemaXORcontent; a parameter withcontent(and noschema) satisfies it.openapi3/media_type.go—MediaType.Validatevalidates the schema only when it is non-nil, so an absent schema is not a validation error.Call path to the panic:
Authentication note:
ValidateRequestvalidates security before parameters, but the panic is reachable without credentials whenever the target operation declares no security requirement, or when noAuthenticationFuncis configured (it is opt-in). A single unauthenticated operation anywhere in the served spec is sufficient. If an operation does declare security and a rejectingAuthenticationFuncis wired, that request is rejected before decoding.PoC
Reproduced end-to-end against
HEAD(30e2923) with a realnet/httpserver and a stockhttp.Client.1. Minimal OpenAPI 3.0.3 document (legal —
doc.Validate()passes). Thecfgquery parameter usescontentwith anapplication/jsonmedia type that has noschema:2. A complete, self-contained program. Drop this into a directory inside a checkout of
github.com/getkin/kin-openapiand run it withgo run .. It loads the document above, assertsdoc.Validate()accepts it (proving reachability), serves it behind request validation exactly as the recommended middleware does, and sends one unauthenticatedGET /c?cfg=1:3. Observed result — the request goroutine panics inside validation, and the client's
http.Getreturns an EOF:Swapping the media type for one that carries a schema (
application/json: {schema: {type: object}}) makes the same request return a clean400instead of panicking, confirming the missing schema is the cause.Impact
This is an unauthenticated remote denial of service (CWE-476) against any service that validates incoming requests with
openapi3filterand serves a spec containing at least onecontentparameter whose media type lacks aschema.The precise consequence depends on which goroutine runs the panic and whether a
recover()covers it:net/http?net/http(incl.openapi3filter.ValidationHandler)http: panic servinglog growth.ValidateRequeston an app-spawned goroutine (fan-out,errgroup, async pre-check)recover().net/httphost (fasthttp adaptor, gRPC-gateway shim, CLI, offline/batch spec validator)This is why the suggested CVSS uses
A:L(Base 5.3): under the recommended synchronousnet/httpwiring the panic is recovered per-connection. Reviewers may reasonably raise it toA:H(Base 7.5) for the spawned-goroutine and non-net/httpintegrations, where a single request kills the process.Remediation (suggested)
Add a
mt.Schema == nilguard mirroring the existingmt == nilguard, so a schema-less content parameter yields a clean validation error instead of a panic:The
unmarshalclosure immediately below already tolerates a nil schema (it checksparamSchema != nil), so returning early on nilmt.Schemais consistent with surrounding intent.Workarounds for consumers, pending a patch:
contentparameter in served specs declares aschema, or reject such specs at load time.ParamDecoderthat guardsmt.Schema == nil.recover()— especially if validation runs off the request goroutine or on a non-net/httphost.Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:LReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
kin-openapi has uncontrolled resource consumption in openapi3filter deepObject query parameter decoding
CVE-2026-77354 / GHSA-xhj3-7xw9-vr34
More information
Details
Summary
An uncontrolled resource consumption vulnerability in
openapi3filterlets any unauthenticated client force multi-gigabyte heap allocation with a single, tiny HTTP request. When a spec declares adeepObject-style query parameter whose schema contains an array (a normal, documented pattern), the decoder reconstructs the array by reading the largest attacker-supplied index and allocating one slot for every position from0up to that index — before schema validation (includingmaxItems) ever runs. A request as small as 24 bytes (?param[items][50000000]=x) drives heap allocation to ~6.1 GiB, reliably triggering an OOM kill / restart loop on memory-constrained services.Details
The OpenAPI
style: deepObjectserialization lets clients express arrays in the query string using bracket notation, e.g.param[items][0]=a¶m[items][1]=b. The decoder first collects these into an intermediatemap[string]anykeyed by the string of the index, then converts that sparse map into a real[]anyinsliceMapToSlice:A second, equally-sized allocation follows immediately in
buildResObj:So a single attacker-chosen integer
Nproduces anappend-grown[]anyof lengthN+1, a secondmake([]any, N+1), andN+1recursion steps — with no upper bound other thanstrconv.Atoi'sintrange (~9.2×10¹⁸ on 64-bit) and available memory.Why
maxItemsdoes not help.maxItemsis enforced by schema validation, which runs strictly after parameter decoding completes.sliceMapToSlice/buildResObjfully materialize the oversized array first; validation only inspects — and rejects — the already-allocated result. The PoC below demonstrates this ordering directly: the returned error is themaxItemsviolation, proving the allocation happened before it could be prevented.Why this is deepObject-specific. Every other array-bearing surface was driven with an equivalent large-index/large-array payload and stayed under ~27 KiB:
application/jsonbodies build arrays element-by-element from the literal (no "index" concept to inflate);x-www-form-urlencodedandmultipart/form-dataarrays are sized by the number of repeated fields actually sent; and the othermakeObjectcall sites (path/simple, header/simple, cookie/form, at:479,:777,:841) build their intermediate map viapropsFromString, which splits on delimiters and produces property-name keys, never bracketed integer indexes. Only the deepObjectpropsFn(:661-687) synthesizes the bracketed integer keys that reachsliceMapToSlicewith an attacker-controlled magnitude.Preconditions. The target spec needs a query parameter with
in: query,style: deepObject(typicallyexplode: true), and a schema whose graph contains at least onetype: array. This is an entirely normal, author-written spec — it is exactly the pattern the library's own decoder tests exercise. No hostile spec authoring is required, and the attack works regardless of anymaxItemsconstraint on the array.Introduced in.
sliceMapToSlice, including the unbounded0..maxfill loop, was added whole-cloth in commit78bb273("openapi3filter: deepObject array of objects and array of arrays support (#923)", merged 2024-03-22), which first shipped inv0.124.0. Every tagged release fromv0.124.0through the currentv0.141.0/master(1d0a337) contains the vulnerable code path.PoC
Verified against revision
1d0a337c9b1570fab283be8a04c8af6e43b9a22c(v0.141.0, currentmasterat the time of writing), Go 1.25.0,darwin/arm64.1. Spec — one operation accepting a
deepObjectquery parameter whoseitemsproperty is an array (maxItems: 3is declared deliberately, to prove it does not help):2. Program — build a request with a single huge array index and measure heap allocation across the same public entry point (
gorillamuxrouter →openapi3filter.ValidateRequest) any real HTTP server uses:3. Observed output (
go run ., unpatched tree, re-verified in this pass):A 24-byte query string drove ~6.1 GiB of heap allocation in a single call, and the returned error is the
maxItemsrejection — proof that the array was fully materialized before validation could reject it. Scaling the index shows the amplification is linear and attacker-tunable (measured over several runs on this revision):param[items][10000]=xparam[items][100000]=xparam[items][1000000]=xparam[items][5000000]=xparam[items][50000000]=xAttack request (nothing else required — no body, no auth, no unusual headers):
Control (confirms only deepObject is a vector): repeating the equivalent "large array" attempt against
application/json,application/x-www-form-urlencoded,multipart/form-databodies, and non-deepObjectpath/header/cookiestyles stays under ~27 KiB in every case.4. Regression/scaling test suite — a broader harness driving the same public entry point, adding the ordering proof (
TestC02_AllocationBeforeValidation), the nested-index amplifier, and the cross-encoding controls referenced above. Save asopenapi3filter/zzz_c02_verify_test.goand run withC02_BIG=1 go test -run TestC02 ./openapi3filter/ -v(unsetC02_BIGto skip the two largest, slower indexes):Observed output re-run in this pass (
C02_BIG=1 go test -run TestC02 ./openapi3filter/ -v):git stash push -- openapi3filter/req_resp_decoder.go):TestC02_Reproduce_MemoryExhaustionreproduced the full scaling table above (10,000 → 937.5 KiB through 50,000,000 → 6.1 GiB), andTestC02_AllocationBeforeValidationmeasured 225.2 MiB allocated forindex=2,000,000before themaxItemsrejection fired — both matching the standalone PoC's findings and failing their bounded-allocation assertions as expected.TestC02_OnlyDeepObjectAffected/TestC02_NonDeepObjectStylesSafeconfirm the other encodings and parameter styles were never affected.Impact
github.com/getkin/kin-openapi/openapi3filterto validate requests against a spec that declares anin: query,style: deepObjectparameter whose schema contains an array anywhere in its property graph. This is a normal, documented OpenAPI pattern, not a hostile or unusual spec.GETrequest with a small, attacker-chosen query string (as few as ~21–24 bytes). No body, no credentials, no special client tooling, no chunked-encoding orContent-Lengthtrickery — the trigger lives entirely in the query string, so request-body size limits do not mitigate it.maxItemsconstraint on the array does not prevent this, because materialization happens during decoding, strictly before schema validation runs.style: deepObjectfor array-bearing query parameters; requests viaapplication/json,x-www-form-urlencoded, ormultipart/form-databodies; andpath/header/cookiestyled object parameters (all verified empirically above, and re-verified in this pass).Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
kin-openapi openai3filter: nil-pointer panic in ConvertErrors on malformed multipart/form-data body enables unauthenticated DoS
CVE-2026-76905 / GHSA-mmfr-pmjx-hw9w
More information
Details
Summary
A nil-pointer dereference in
openapi3filter.ConvertErrorslets any unauthenticated client crash a server with a single HTTP request. When an application validates amultipart/form-datarequest body and renders the resulting validation error through the library-providedValidationErrorEncoder/ConvertErrorshelpers, a malformed scalar form field (e.g. a non-numeric value for anintegerproperty) produces an error shape thatconvertParseErrordereferences without a nil check. The handler goroutine panics, causing a denial of service.application/jsonrequest bodies are not affected — the bug is specific tomultipart/form-data.Details
The panic is in
convertParseError, atopenapi3filter/validation_error_encoder.go:119-120(still present onmasterat the time of writing):The comparison
e.Parameter.In == "query"assumese.Parameteris non-nil. It is reached whenever both of the following hold:e.Parameter == nil. A*RequestErrorcarries eitherParameter(parameter errors) orRequestBody(body errors), never both.ValidateRequestBodybuilds body errors with onlyRequestBodyset, leavingParameternil — seevalidate_request.go:326-332.innerErr.Causeis itself a*ParseError(aParseErrornested inside aParseError), so the type assertion on line 119 succeeds and execution reaches thee.Parameter.Indereference on line 120.The only default code path that satisfies both conditions is the multipart body decoder, which wraps a failed part's
*ParseErrorinside another*ParseErroratreq_resp_decoder.go:1549and:1558:Why other paths do not reach the dereference:
RequestError.Errshape.Causeis*ParseError?e.Parametermultipart/form-dataage=notanumber)*ParseErrorwrapping a*ParseErrornilapplication/json*ParseErrorwhose.Causeis anencoding/jsonerrornilapplication/json*openapi3.SchemaError(routed toconvertSchemaError, never reachesconvertParseError)nilquery/pathparams*ParseErrorwrapping a*ParseErrorNote that the sibling
"path"branch two lines above (line 108) already guards correctly withe.Parameter != nil; the"query"branch simply omits the same guard.Recommended fix. Add the missing nil guard to the condition:
When
e.Parameter == nilthe innerifis skipped and control falls through to the existingreturn &ValidationError{Status: http.StatusBadRequest, Title: innerErr.Reason}at line 127-130 — a correct400 Bad Request. I verified that applying only this one-line guard stops the panic and returns*ValidationError{Status: 400}.Minor follow-up worth including in the same change: for the multipart nested
*ParseError, the outerParseError.Reasonis empty, so the fallbackTitle: innerErr.Reasonyields a400with an emptyTitle. The descriptive text lives ininnerErr.Error()(e.g."path age: value notanumber: an invalid integer: invalid syntax"). Prefer a non-empty fallback:PoC
Verified against revision
98d956447b64eaa10d3570a80b3be1a2849945f1(also reproducible on currentmaster), Go 1.25.0.1. Spec — one operation accepting a
multipart/form-databody with a non-string scalar (integer) property:2. Program — validate a request whose
agepart is non-numeric, then convert the error the way a typical error-rendering middleware does:3. Observed output (
go run .):The panic is at exactly
validation_error_encoder.go:120— the unguardede.Parameter.Indereference.Control (confirms JSON is not a vector): repeating the setup with an
application/jsonbody and either a malformed body ({"age":) or a wrong-type body ({"age": "notanumber"}) returns fromConvertErrorsnormally, with no panic. Only themultipart/form-datapath crashes.In a real HTTP server,
ConvertErrors/ValidationErrorEncoder.Encoderuns inside the request handler, so the panic aborts the in-flight request (connection reset / 500) and, without arecover()in the middleware chain, is trivially repeatable.Impact
github.com/getkin/kin-openapi/openapi3filterthat (1) exposes an endpoint accepting amultipart/form-datarequest body with at least one non-string scalar property (integer/number/boolean), and (2) renders validation errors through the library's ownValidationErrorEncoderorConvertErrorshelpers. These are the library's advertised error-rendering helpers, so this is a realistic default integration.recover()boundary in the application's middleware, the request is aborted; sustained requests deny service. Confidentiality and integrity are not affected.application/jsonbodies (verified above), applications that do not useConvertErrors/ValidationErrorEncoderto format errors, or applications that wrap handlers in arecover()(which converts the crash into a handled 500 but still prevents normal error rendering).Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HReferences