Vulnerability GHSA-rj39-cv6w-8wv7

High Risk
HIGH RISK
CVSS Score: 7.5
Score Range: 7.0–8.9
High severity vulnerabilities (CVSS 7.0–8.9). Serious vulnerabilities that should be prioritized soon after critical fixes.
6 hours ago
October 15, 2026 at 08:20 PM UTC
kin-openapi: YAML NaN/Inf Values Bypass Built-in Guards and Panic via OAS 3.1 Validation Path
v0.1.0 - v0.147.0
v0.1.0 - v0.147.0

Summary

kin-openapi: YAML NaN/Inf Values Bypass Built-in Guards and Panic via OAS 3.1 Validation Path

Details

Summary

kin-openapi guards against NaN and Inf values in its built-in schema visitor (visitJSON) by returning ErrSchemaInputNaN / ErrSchemaInputInf when a float64 input violates those constraints. For OAS 3.1 specs, however, Schema.VisitJSON routes through useJSONSchema2020, which hands the value directly to santhosh-tekuri/jsonschema/v6 v6.0.2 without applying the same guard.

Inside jsonschema/v6 v6.0.2, numValidate builds a *big.Rat from the input via big.Rat.SetString(fmt.Sprintf("%v", v)). For NaN/Inf this parse fails silently and returns nil. numValidate then dereferences the nil *big.Rat (in math/big.(*Rat).Cmp), producing a Go runtime panic.

An attacker delivers this by sending an HTTP request with Content-Type: application/yaml (or application/x-yaml) and a YAML body containing .nan, .inf, or -.inf. The YamlBodyDecoder decodes those tokens into math.NaN() / math.Inf(±1) (standard YAML 1.2 behavior), and they propagate to the unguarded useJSONSchema2020 path whenever the schema declares a numeric constraint (minimum, maximum, exclusiveMinimum, exclusiveMaximum, or multipleOf).

Details

Root Cause

The built-in visitor visitJSON at openapi3/schema.go:1968 guards NaN/Inf explicitly:

case float64:
    if math.IsNaN(value) {
        return ErrSchemaInputNaN
    }
    if math.IsInf(value, 0) {
        return ErrSchemaInputInf
    }

For OAS 3.1 specs, VisitJSON dispatches to useJSONSchema2020 (openapi3/schema_jsonschema_validator.go:204), which contains no such guard:

func (schema *Schema) useJSONSchema2020(settings *schemaValidationSettings, value any) error {
    validator, err := newJSONSchemaValidator(schema)
    if err != nil {
        return schema.visitJSON(settings, value)
    }
    return validator.validate(value)      // value handed straight through
}

jsonSchemaValidator.validate calls jsonschema/v6.Schema.Validate (line 146), which reaches numValidate in v6.0.2. There, big.Rat.SetString(fmt.Sprintf("%v", v)) returns (nil, false) for NaN/Inf, and the code dereferences the nil *big.Rat in Rat.Cmp, causing the panic.

Proof of Concept

Environment

  • kin-openapi v0.144.0 (tag v0.144.0, commit f0407d5)
  • santhosh-tekuri/jsonschema/v6 v6.0.2 (transitive dep)
  • Go 1.26.7

Spec

Minimal OAS 3.1 spec (spec.yaml) declaring a YAML body with a numeric constraint:

openapi: '3.1.0'
info: { title: Test, version: '1.0' }
paths:
  /test:
    post:
      requestBody:
        required: true
        content:
          application/yaml:
            schema:
              type: number
              minimum: 0
      responses:
        '200': { description: OK }

Trigger

A single POST /test with Content-Type: application/yaml and body .nan, .inf, or -.inf. All three variants panic:

=== RUN   TestNaNInf
[nan]    PANIC (confirms vuln): runtime error: invalid memory address or nil pointer dereference
[inf]    PANIC (confirms vuln): runtime error: invalid memory address or nil pointer dereference
[neginf] PANIC (confirms vuln): runtime error: invalid memory address or nil pointer dereference

Panic stack trace (confirms exact chain)

panic: runtime error: invalid memory address or nil pointer dereference

math/big.(*Rat).Cmp(0x0, ...)                                       <- nil *big.Rat dereferenced
    C:/Program Files/Go/src/math/big/rat.go:492
github.com/santhosh-tekuri/jsonschema/v6.(*validator).numValidate(...)
    .../jsonschema/[email protected]/validator.go:525
github.com/santhosh-tekuri/jsonschema/v6.(*validator).validate(...)
    .../jsonschema/[email protected]/validator.go:168
github.com/santhosh-tekuri/jsonschema/v6.(*Schema).validate(...)
    .../jsonschema/[email protected]/validator.go:34
github.com/getkin/kin-openapi/openapi3.(*jsonSchemaValidator).validate(...)
    openapi3/schema_jsonschema_validator.go:146
github.com/getkin/kin-openapi/openapi3.(*Schema).useJSONSchema2020(...)   <- MISSING NaN/Inf guard
    openapi3/schema_jsonschema_validator.go:211
github.com/getkin/kin-openapi/openapi3.(*Schema).VisitJSON(...)
    openapi3/schema.go:1946
github.com/getkin/kin-openapi/openapi3filter.ValidateRequestBody(...)
    openapi3filter/validate_request.go:364
github.com/getkin/kin-openapi/openapi3filter.ValidateRequest(...)
    openapi3filter/validate_request.go:96

net/http behavior (severity nuance)

Behind a standard net/http server, the panic is recovered per-connection. The client sees a dropped connection; the server process continues:

Sending POST /test body=.nan against real net/http server...
2026/08/25 http: panic serving 127.0.0.1:40625: runtime error: invalid memory address or nil pointer dereference
CLIENT ERROR (connection dropped): Post ".../test": EOF
Process still alive after request: true

This is a recoverable panic, unlike the recursion finding. recover() catches it (verified by capturing the panic value in a defer in the same goroutine). Non-net/http hosts or validation performed in an application-spawned goroutine are not covered by that recovery and would experience a full-process crash.

Fix verification

Upgrading only the transitive dependency to jsonschema/[email protected] (via go get github.com/santhosh-tekuri/jsonschema/[email protected]) eliminates the panic entirely; all three payloads return a clean validation error:

[nan]    Returned normally, err = request body has an error: doesn't match schema: validation failed due to: at '': invalid jsonType float64
[inf]    Returned normally, err = request body has an error: doesn't match schema: validation failed due to: at '': invalid jsonType float64
[neginf] Returned normally, err = request body has an error: doesn't match schema: validation failed due to: at '': invalid jsonType float64

This confirms the upstream jsonschema/v6 v6.0.3 release treats the NaN/Inf case as a bug and fixes it at the source. It also confirms useJSONSchema2020 is the reachable path: patching only the transitive dep removes the panic without touching kin-openapi code.

Why This Is a Vulnerability, Not by Design

  • The library explicitly refuses NaN/Inf in its own visitor (ErrSchemaInputNaN / ErrSchemaInputInf at schema.go:1968). The stated policy is: these values are not allowed.
  • The OAS 3.1 dispatch (useJSONSchema2020) simply omits the same guard — a coding gap, not a design decision.
  • Upstream jsonschema/v6 v6.0.3 fixes the same case as a bug. Two independent code owners agree it should not panic.
  • The trigger is a single HTTP request body an unauthenticated client can send. There is no legitimate content-authoring reason to submit .nan / .inf as a numeric field.

Impact

  • Per-request denial of service (net/http hosts). Every crafted request kills its own connection with zero attacker cost. Sustained flooding degrades service reliability and log noise.
  • Full-process denial of service (non-net/http hosts or goroutine-spawned validation). No net/http recovery wrapper is present; the whole process crashes on a single request.
  • Attack surface is any OAS 3.1 API that accepts YAML bodies with numeric constraints. These constraints (minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf) are common on any numeric field with a range.

Timeline

Published
6 hours ago
October 15, 2026 at 08:20 PM UTC
Fixed (v0.148.0)
1 month ago
August 27, 2026 at 10:09 AM UTC
Last Modified
5 hours ago
October 15, 2026 at 08:30 PM UTC