DEV Community

Faizan Akhtar
Faizan Akhtar

Posted on Originally published at faizanakhtarcyber.blogspot.com

CVE-2026-108551: openapi-typescript-codegen Handlebars Code Injection Vulnerability — Analysis & Mitigation

Originally published at https://faizanakhtarcyber.blogspot.com/2026/10/cve-2026-108551-openapi-typescript-codegen-handlebars-injection-analysis.html

On October 10, 2026, the NVD published CVE-2026-108551, a critical code injection vulnerability in openapi-typescript-codegen, the npm package that converts OpenAPI documents into typed TypeScript API clients — downloaded roughly 600,000 times a week. A single apostrophe inside a malicious API specification can break out of a generated string literal and inject live JavaScript into every client the tool produces. For the security of cyberspace, the twist is the target: this bug does not attack your application — it attacks your build pipeline, poisoning the code before your application even exists.

Summary

openapi-typescript-codegen is a Node.js library that reads an OpenAPI (Swagger) document and generates a ready-to-use TypeScript API client. CVE-2026-108551 is a CWE-94 code injection flaw in the Handlebars templates the generator uses to build that client. The templates interpolate spec-controlled values with Handlebars' triple-stash syntax ({{{...}}}) — which writes values out unescaped — directly inside single-quoted JavaScript string literals. Affected slots include BASE: '{{{server}}}' and VERSION: '{{{version}}}' in the generated config, method: '{{{method}}}' and url: '{{{path}}}' per request, and '{{{prop}}}': as parameter keys for path, cookie, header, query, and form params.

The result: anyone who controls or influences an OpenAPI document processed by your build — a vendor's published spec, a partner's API definition, an internal service registry, a public repo — can embed a single quote plus a JavaScript payload in a path key, a parameter name, servers[0].url, or info.version. The generated client then contains executable attacker code that runs when the client is imported or a service method is called.

The sting: no patched version exists. Version 0.31.0 (June 2026) is the newest release, and the promised fix — including an npm deprecation in favor of its successor — was never applied. Every released version, 0 through 0.31.0, is affected.

Severity

  • CVE ID: CVE-2026-108551
  • CVSS 3.1: 9.8 Critical (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
  • CVSS 4.0: 9.3 Critical (AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N)
  • Weakness: CWE-94 — Improper Control of Generation of Code ('Code Injection')
  • Reported by: researcher George Chen; CNA: VulnCheck
  • Attack requirements: none against the pipeline — the attacker only needs influence over an OpenAPI document the victim's tooling consumes
  • Impact: arbitrary JavaScript execution in the build environment (secrets theft, CI/CD compromise) and in every consumer of the generated client (XSS-equivalent in browsers)
  • Exploited in the wild: no confirmed reports; not in the CISA KEV catalog

The 9.8 is honest: network-reachable, trivial complexity, zero privileges, full confidentiality/integrity/availability impact. The "network" here is your dependency supply chain — which is reachable by design.

Affected Versions

  • openapi-typescript-codegen 0 through 0.31.0, inclusive — all 109 published npm versions
  • Fixed in: nothing — no patched release exists; 0.31.0 (June 20, 2026) is still the latest on the registry
  • Vulnerable injection points: request path keys, path/query/header/cookie/form parameter names, request-body media types, response header names, servers[0].url, and info.version
  • All generated HTTP clients affected: fetch, axios, xhr, node, and angular variants
  • Exposure: any pipeline that generates clients from specs you do not fully control — vendor specs, partner APIs, service registries, auto-ingested remote URLs in CI

If your CI runs generation automatically on every build against a remote spec URL, you are running attacker-influenced code generation on a schedule, inside an environment that holds your deployment secrets.

Technical Analysis

Three Braces and a Single Quote

In Handlebars, {{value}} HTML-escapes its output while {{{value}}} — the triple-stash — writes it raw. Template authors reach for the triple-stash when the value legitimately contains characters that escaping would mangle, like the & in a URL. The generator's templates needed raw server URLs and paths, so the author wrote BASE: '{{{server}}}', — and in doing so, handed the OpenAPI document direct write access to the generated JavaScript source.

The exploit is textbook string-literal breakout. Suppose servers[0].url is https://api.example.com/'; PAYLOAD; //. The generator emits BASE: 'https://api.example.com/'; PAYLOAD; //', — the first quote closes the literal, the payload executes as ordinary JavaScript, and the trailing // comments out the leftover quote. From there the payload does anything JavaScript can do in that context: in a Node build step it reads process.env and exfiltrates CI secrets; in a browser bundle it runs with the application's origin and session.

Nobody code-reviews a code generator's output line by line — that is the point of using one. Linters won't flag it, type-checkers won't flag it, and once committed, the payload inherits the trust of your own repository.

Supply-Chain Arithmetic: Poisoning Code Before It Exists

Most supply-chain attacks poison something you install — a compromised package, a typosquatted dependency. CVE-2026-108551 poisons something you generate, which is harder to detect: the malicious artifact is produced by your own trusted tooling, then signed, built, and shipped by you. The trust boundary crossed is not "do I trust this package" but "do I trust every OpenAPI document my tooling has ever consumed" — and most organizations cannot answer that, because specs flow in from vendors, partners, and registries with no integrity checks.

Do the arithmetic: one compromised vendor spec, auto-ingested by CI across ten client teams, produces ten poisoned generated clients, each shipped to production, each executing the attacker's JavaScript. The blast radius multiplies at every layer — build environment, generated code, downstream consumers — while the evidence (a quote character in a YAML file somewhere) stays nearly invisible. This is why the security of cyberspace increasingly depends on build-pipeline hygiene, not just application code.

Pentest Playbook: Weaponizing an OpenAPI Spec

On a pentest, this vulnerability gives you a phishing-free path into the build environment. The recon is simple: OpenAPI documents sit at predictable locations (/openapi.json, /v3/api-docs, /swagger.json) or ship to partners as integration artifacts. During scoping, determine whether the target generates clients — check CI configs for codegen steps, look for generated client directories, and ask which specs feed them.

A pen test demo: (1) identify an auto-ingested spec (a vendor integration or registry entry you can influence); (2) inject a quote-breakout payload into info.version or a parameter name; (3) show the generated diff containing live JavaScript; (4) demonstrate execution at import time in the build container — reading a canary secret from the environment proves CI compromise without touching production.

Why This Matters

Build pipelines are the soft underbelly of modern software delivery. The tool that writes your code for you becomes the attacker's code writer, inheriting every privilege your build holds.

What does vulnerable mean when the flaw lives in your build tools? It means your application can be compromised without a single bug in your application — the poison enters one step earlier, in the generated code you never wrote and never reviewed. Why should every pentest scope include the code generator? Because attackers follow trust, and nothing in your organization is more trusted — or less scrutinized — than the tooling that produces your source code.

Mitigation

  • There is no patch — 0.31.0 is the latest release and no fixed version exists. Mitigation is procedural until the maintainer ships a fix.
  • Generate only from specs you trust: stop auto-generating clients from remote spec URLs in CI. Vendor specs locally, review them, and generate from the vendored copy.
  • Review generated-code diffs: treat generated output as untrusted input — require human or automated review of every generated diff before it is committed or built.
  • Pin and audit: pin the package version, run npm ls openapi-typescript-codegen across your repos to find every consumer, and flag any pipeline that ingests third-party specs.
  • Sandbox the generation step: run codegen in an ephemeral container with no deployment secrets in the environment, so a successful injection still cannot reach anything valuable.
  • Evaluate maintained alternatives: the package has seen no release since June 2026 and the promised deprecation never happened — plan a migration path to an actively maintained generator.

References

Report by Faizan Akhtar — The Cyber Security Researcher

Top comments (0)