high

CVE

CVE-2026-119028, CVE-2026-119027, CVE-2026-118764, CVE-2026-118664, CVE-2026-118763, CVE-2026-62374, CVE-2026-119051

CWE

CWE-94, CWE-400, CWE-407, CWE-522, CWE-347, CWE-770

Affected Surface

  • Go module `github.com/oapi-codegen/oapi-codegen/v2` versions `>= 2.0.0, < 2.8.1` (`CVE-2026-119028` / `GHSA-xrqw-w576-xgj2`, CVSS 8.8) and `>= 2.5.0, < 2.8.1` (`CVE-2026-119027` / `GHSA-rjwr-m7qx-3fjr`, CVSS 7.5; plus `GHSA-g2vv-83pm-v2hc`)
  • npm `minimatch` versions `< 11.0.1` (`CVE-2026-118764` / `GHSA-g3hv-75wg-m249`, CVSS v4.0 8.7 High, when `optimizationLevel >= 2`)
  • npm `decode-uri-component` versions `<= 0.5.0` (`CVE-2026-118664` / `GHSA-qr28-fpjm-wq7f`, CVSS v4.0 8.2 High)
  • npm `@sigstore/oci` versions `< 0.7.2` (`CVE-2026-118763` / `GHSA-j63v-mwhm-56jx`, CVSS 7.4 High)
  • npm `@sd-jwt/core` and `@sd-jwt/decode` versions `<= 0.19.0` (`CVE-2026-62374` / `GHSA-f9j6-8p6x-r9j6`, CVSS v4.0 7.1 High)
  • npm `flat` versions `<= 6.0.1` (`CVE-2026-119051`, CVSS v4.0 8.2 High / v3.1 5.9 Medium, unpatched upstream)

TL;DR

On 29 October 2026, NVD and the GitHub Advisory Database published seven advisories across foundational Go code generation and JavaScript/TypeScript packages:

  1. Go oapi-codegen < 2.8.1 (CVE-2026-119028, CVSS 8.8 High; CVE-2026-119027, CVSS 7.5 High; and GHSA-g2vv-83pm-v2hc): When generating Go client or server code from an OpenAPI specification, constants.tmpl emitted non-string enum values (integer, number, boolean) into a const (...) block without quoting or validating that they were numeric/boolean literals (CVE-2026-119028), and server-urls.tmpl emitted servers[].x-go-name, server variable names, and undeclared {placeholder} names directly as Go identifiers (CVE-2026-119027). An untrusted or third-party OpenAPI spec could close the const block and inject a func init() { ... } block that executes automatically when the generated Go package is built or tested. Version 2.8.1 (commit 068f1bcd16) also fixes template injection via Echo operationId middleware keys, toStringArray trailing-backslash security scopes, x-go-type-import aliases, response status keys, and webhook/Fiber ContentType strings.
  2. minimatch < 11.0.1 (CVE-2026-118764 / GHSA-g3hv-75wg-m249, CVSS v4.0 8.7 High): At optimizationLevel: 2 or higher, firstPhasePreProcess() split <pre>/**/../<p>/<rest> into <pre>/{..,**}/<p>/<rest> inside a do { ... } while (didSomething) loop without checking braceExpandMax, doubling the pattern array on each **/.. segment, and secondPhasePreProcess() compared every expanded pattern pairwise (O(n^2)). A 30-segment **/../a/b pattern expanded to 2^30 entries and hung the Node.js process. Fixed in 11.0.1 (11.0.3 current).
  3. decode-uri-component <= 0.5.0 (CVE-2026-118664 / GHSA-qr28-fpjm-wq7f, CVSS v4.0 8.2 High): When decodeURIComponent() threw on a malformed tail (such as %zz), the fallback customDecodeURIComponent() collected every distinct %XX sequence into replaceMap and ran input.replace(new RegExp(key, 'g'), replaceMap[key]) across the entire string for each entry. Thirty-two thousand distinct percent-encoded runs plus a trailing %zz blocked the Node.js event loop for ~20 seconds. Fixed in 0.5.1 via single-pass linear decoding.
  4. @sigstore/oci < 0.7.2 (CVE-2026-118763 / GHSA-j63v-mwhm-56jx, CVSS 7.4 High): RegistryClient.signIn() attached registry Authorization and Docker config headers as defaults on the shared HTTP client, and RegistryClient.uploadBlob() issued a fresh PUT to whatever absolute Location URL the registry returned from POST /v2/<repo>/blobs/uploads/ without checking its origin or scheme. Because the PUT was a new request rather than an HTTP redirect, redirect header-stripping never ran, leaking registry bearer tokens or Basic credentials to an attacker-chosen upload host. Fixed in @sigstore/oci@0.7.2.
  5. @sd-jwt/core and @sd-jwt/decode <= 0.19.0 (CVE-2026-62374 / GHSA-f9j6-8p6x-r9j6, CVSS v4.0 7.1 High) and flat <= 6.0.1 (CVE-2026-119051, CVSS v4.0 8.2 High): @sd-jwt/decode silently dropped tampered or invalid-UTF-8 Selective Disclosure JWT disclosures whose digest did not match the Issuer-signed _sd array instead of rejecting the presentation per RFC 9901 Section 7.1, allowing a holder to strip restrictive claims (age, role, restriction) while verification succeeded (fixed in @sd-jwt/core@0.20.0; @sd-jwt/decode standalone remains unpatched). In flat <= 6.0.1, unflatten() converts any bare numeric key (such as {"a.4294967294": 1}) into an array index without an upper bound, creating a 4.29-billion-element sparse array that locks up Node.js on JSON.stringify or .forEach().

What to do now: Upgrade github.com/oapi-codegen/oapi-codegen/v2 to >= v2.8.1, minimatch to >= 11.0.1 (11.0.3 current), decode-uri-component to >= 0.5.1, @sigstore/oci to >= 0.7.2, and @sd-jwt/core to >= 0.20.0 (0.24.0 current, and remove direct imports of @sd-jwt/decode). For flat <= 6.0.1, pass { object: true } to unflatten() when handling untrusted keys.

Affected packages and projects

EcosystemPackageCVE / GHSASeverityAffected versionsFixed versionVulnerable component
Gogithub.com/oapi-codegen/oapi-codegen/v2CVE-2026-119028 (GHSA-xrqw-w576-xgj2), CVE-2026-119027 (GHSA-rjwr-m7qx-3fjr), GHSA-g2vv-83pm-v2hcCVSS 8.8 / 7.5 High>= 2.0.0, < 2.8.1 (119028); >= 2.5.0, < 2.8.1 (119027)2.8.1pkg/codegen/codegen.go (GenerateEnums), templates/constants.tmpl, templates/server-urls.tmpl, validate_spec.go
npmminimatchCVE-2026-118764 (GHSA-g3hv-75wg-m249)CVSS v4.0 8.7 High< 11.0.1 (optimizationLevel >= 2)11.0.1 (11.0.3 current)src/index.ts (firstPhasePreProcess, secondPhasePreProcess)
npmdecode-uri-componentCVE-2026-118664 (GHSA-qr28-fpjm-wq7f)CVSS v4.0 8.2 High<= 0.5.00.5.1index.js (customDecodeURIComponent)
npm@sigstore/ociCVE-2026-118763 (GHSA-j63v-mwhm-56jx)CVSS 7.4 High< 0.7.20.7.2packages/oci/src/registry.ts (RegistryClient.signIn, uploadBlob), credentials.ts
npm@sd-jwt/core, @sd-jwt/decodeCVE-2026-62374 (GHSA-f9j6-8p6x-r9j6)CVSS v4.0 7.1 High<= 0.19.0@sd-jwt/core 0.20.0 (0.24.0 current; @sd-jwt/decode unpatched)packages/core/src/decode/decode.ts, packages/core/src/sdjwt.ts
npmflatCVE-2026-119051CVSS v4.0 8.2 High (v3.1 5.9 Medium)<= 6.0.1None (pass { object: true } to unflatten())index.js (getkey, unflatten)

Technical analysis

1. Go oapi-codegen 2.8.1 (CVE-2026-119028 and CVE-2026-119027): Go source injection via non-string enums, server-urls, and operationId

In oapi-codegen, pkg/codegen/templates/constants.tmpl renders enum constants for each schema that defines an enum array:

{{range $Enum := .EnumDefinitions}}
// Defines values for {{$Enum.TypeName}}.
const (
{{range $name, $value := $Enum.GetValues}}
  {{$name}} {{$Enum.TypeName}} = {{if $Enum.ValueWrapper}}{{$value | toGoString}}{{else}}{{$value}}{{end -}}
{{end}}
)

For string enums, $Enum.ValueWrapper is " and $value is escaped via toGoString. For integer, number, and boolean schemas, $Enum.ValueWrapper is empty, so $value was interpolated raw into the Go source file (CVE-2026-119028 / GHSA-xrqw-w576-xgj2). Because OpenAPI YAML/JSON parsers allow arbitrary values inside an enum: list unless validated, a spec containing:

components:
  schemas:
    Count:
      type: integer
      enum:
        - "1)\nfunc init() { /* arbitrary Go code */ }\nconst (_ Count = 2"

closed the const (...) block and emitted a top-level func init() that ran as soon as a developer or CI pipeline compiled or tested the package. Similarly, in pkg/codegen/templates/server-urls.tmpl (CVE-2026-119027 / GHSA-rjwr-m7qx-3fjr), const {{ .GoName }} = ... and func New{{ .GoName }}(...) emitted servers[].x-go-name, server variable names, and undeclared {placeholder} names without checking that they were valid Go identifiers.

Commit 068f1bcd16 (PR #2626, released in v2.8.1) hardens GenerateEnums() and adds ValidateServerURLs() and spec-wide escaping across seven additional template sinks:

--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -1533,6 +1537,19 @@ func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error)
+	for _, e := range enums {
+		if e.ValueWrapper != "" {
+			continue
+		}
+		for _, value := range SortedMapKeys(e.Schema.EnumValues) {
+			if !isNumberOrBoolLiteral(e.Schema.EnumValues[value]) {
+				return "", fmt.Errorf("enum value %q of %s is not a number or boolean literal, which its Go type %s requires", e.Schema.EnumValues[value], e.TypeName, e.Schema.GoType)
+			}
+		}
+	}

The same commit also replaces options.OperationMiddlewares["{{.MiddlewareKey}}"] with {{.MiddlewareKey | toGoString}} in Echo v4/v5 templates, quotes each security scope with strconv.Quote in toStringArray() (fixing a trailing-backslash quote escape), validates x-go-type-import.name as a Go identifier, restricts response keys to ^(default|[1-5]XX|[1-9][0-9][0-9])$, and passes {{.ContentType | toGoString}} in webhook-initiator.tmpl, callback-initiator.tmpl, and strict-fiber-v3.tmpl.

2. minimatch 11.0.1 (CVE-2026-118764) and decode-uri-component 0.5.1 (CVE-2026-118664): exponential glob expansion and quadratic URI fallback

In minimatch (< 11.0.1), passing { optimizationLevel: 2 } activates firstPhasePreProcess() and secondPhasePreProcess() in src/index.ts. Whenever firstPhasePreProcess() encountered <pre>/**/../<p>/<rest>, it split the pattern into two branches (.. and **) and set didSomething = true, repeating the do { ... } while (didSomething) loop over the newly pushed branches without checking braceExpandMax. Thirty **/../a/b segments doubled globParts 30 times, and secondPhasePreProcess() then ran a nested O(n^2) deduplication loop over the expanded set. Commit 77a0f5c4b8 stops splitting **/.. once globParts.length >= braceExpandMax (default 100,000) and skips pairwise deduplication when globParts.length > 1000:

--- a/src/index.ts
+++ b/src/index.ts
@@ -1178,7 +1183,8 @@ export class Minimatch {
             p === '..' ||
             !p2 ||
             p2 === '.' ||
-            p2 === '..'
+            p2 === '..' ||
+            globParts.length >= braceExpandMax
           ) {
             continue
           }
@@ -1242,6 +1248,9 @@ export class Minimatch {
   secondPhasePreProcess(globParts: string[][]): string[][] {
+    if (globParts.length > 1000) return globParts
     for (let i = 0; i < globParts.length - 1; i++) {

In decode-uri-component (<= 0.5.0), decodeUriComponent(input) first tries decodeURIComponent(input) and falls back to customDecodeURIComponent(input) on URIError. Previously, customDecodeURIComponent() matched every percent-encoded run, stored its decoded value in replaceMap[match], and then iterated for (const key of Object.keys(replaceMap)) { input = input.replace(new RegExp(key, 'g'), replaceMap[key]); }. When a request body or query string contained 32,000 distinct valid runs (%00%00x%00%01x...) followed by a single invalid %zz at the end, the fallback compiled and executed 32,000 full-string regex replacements over a ~220 KB string (~20 seconds of synchronous CPU time). Commit fad01d65b9 (0.5.1) replaces the replaceMap regex loop with a single linear pass (decode(input)).

3. @sigstore/oci 0.7.2 (CVE-2026-118763) and @sd-jwt/core 0.20.0 (CVE-2026-62374)

In @sigstore/oci (< 0.7.2), RegistryClient.signIn() stored registry Authorization and custom Docker headers as default headers on the client instance, and RegistryClient.uploadBlob() initiated a blob upload (POST /v2/<repo>/blobs/uploads/) and then sent an explicit PUT request to the URL returned in the Location response header. In the OCI Distribution Spec, Location frequently points to a separate blob-storage host. Because uploadBlob() constructed a new PUT request to that Location URL rather than following an HTTP 307 redirect, redirect-level credential stripping never triggered, and the client sent the registry’s Authorization bearer token or Basic credentials straight to the external host. Commit b855f46cfe and commit e4ca65c3ab (@sigstore/oci@0.7.2) scope registry credential headers strictly to the registry origin, enforce exact-host Docker Hub alias matching (DOCKER_HUB_ALIASES.has(registry) instead of registry.endsWith('docker.io')), and block non-HTTPS or private-IP destinations unless --allow-private-origin (fetchOpts.allowedPrivateOrigins) is explicitly configured.

In @sd-jwt/core and @sd-jwt/decode (<= 0.19.0, CVE-2026-62374 / GHSA-f9j6-8p6x-r9j6), unpackObjInternal() and unpackArray() built a map[digest] = disclosure lookup table from the presented Disclosures and then walked the Issuer-signed _sd digest array. Any Disclosure in the presentation whose digest did not match an entry in _sd (because the holder tampered with the Disclosure or inserted invalid UTF-8 bytes that TextDecoder replaced with U+FFFD) simply went unused in map without raising an error, violating RFC 9901 Section 7.1 Step 5. If a verifier checked for a negative or constraining attribute (such as an age or role restriction) and defaulted to permitting access when that claim was absent, a holder could corrupt that single Disclosure to silently strip the claim while the Issuer signature and Key Binding JWT remained valid. Commit c7cf23dbc1 (@sd-jwt/core@0.20.0, PR #389) enforces strict base64url/UTF-8 JSON decoding (decodeBase64urlJsonStrict), rejects unreferenced and duplicate disclosure digests, and rejects bare JWTs lacking an SD-JWT ~ separator.

Detection and remediation

# 1. Check Go repositories for vulnerable oapi-codegen versions (< v2.8.1)
rg -n 'oapi-codegen' go.mod go.sum Makefile generate.go 2>/dev/null
go version -m $(which oapi-codegen 2>/dev/null) 2>/dev/null || true

# 2. Check Node.js dependency trees and lockfiles
npm ls minimatch decode-uri-component @sigstore/oci @sd-jwt/core @sd-jwt/decode flat 2>/dev/null || true

rg -n '"(minimatch|decode-uri-component|@sigstore/oci|@sd-jwt/(core|decode)|flat)"' \
  package.json package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null

# 3. Search codebases for minimatch optimizationLevel >= 2 or flat unflatten() without { object: true }
rg -n '\b(optimizationLevel|unflatten)\b' --glob '*.{js,ts,mjs,cjs}' . 2>/dev/null
  1. Upgrade oapi-codegen to >= v2.8.1 and regenerate any Go code produced from external or partner OpenAPI specifications:
    go get github.com/oapi-codegen/oapi-codegen/v2@v2.8.1
  2. Upgrade npm dependencies:
    • minimatch: upgrade to >= 11.0.1 (11.0.3 is latest).
    • decode-uri-component: upgrade to >= 0.5.1.
    • @sigstore/oci and @sigstore/cli: upgrade to @sigstore/oci >= 0.7.2. If you push attestations to a private HTTP registry, pass --allow-private-origin <scheme://host:port>.
    • @sd-jwt/core: upgrade to >= 0.20.0 (0.24.0 is latest) and replace any direct usage of the standalone @sd-jwt/decode package with @sd-jwt/core.
    • flat: when calling unflatten() on untrusted JSON keys, pass unflatten(data, { object: true }) or reject dotted segments containing integers larger than your expected array bound before calling unflatten().

Timeline

  • 2026-07-18 to 2026-08-29: OpenWallet Foundation merges PR #389 (c7cf23dbc1) in sd-jwt-js, shipping @sd-jwt/core@0.20.0.
  • 2026-08-04: Sigstore releases @sigstore/oci@0.7.2 with commits b855f46cfe and e4ca65c3ab.
  • 2026-10-23: decode-uri-component releases 0.5.1 (fad01d65b9).
  • 2026-10-28: oapi-codegen releases v2.8.1 (068f1bcd16, PR #2626) and minimatch releases 11.0.1 (77a0f5c4b8).
  • 2026-10-29 (12:17 to 17:18 UTC): NVD and the GitHub Advisory Database publish CVE-2026-119027, CVE-2026-119028, CVE-2026-119051, CVE-2026-118664, CVE-2026-118763, CVE-2026-118764, and CVE-2026-62374.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.

References