Filesystem error messages reflected to clients disclose absolute server paths
info-leak · server.js:40-41
f87c6fc2fa by Macintosh1011 on 2026-05-30Summary
The /api/file endpoint passes raw Node.js fs error messages directly into the 404 response body. When fs.readFile fails, the underlying ENOENT (or EACCES/EISDIR) error string includes the fully-resolved absolute path that __dirname expands to, exposing internal directory structure. The handler should return a generic error and log the detailed message server-side instead.
Impact. An unauthenticated attacker can probe arbitrary filenames and read the server's reflected error messages to learn the absolute deployment path (e.g. /Users/macintosh/Documents/Claude/Projects/.../public/), the username, project layout, and whether specific files exist or are merely unreadable. This information materially aids further attacks such as path-traversal exploitation, targeted LFI, and reconnaissance for credential or config file locations.
Vulnerable code — server.js
🔴 fs.readFile(path.join(__dirname, "public", name), "utf8", (err, data) => {🔴 if (err) return send(res, 404, `not found: ${err.message}`);
Working exploit
curl -s 'http://127.0.0.1:4600/api/file?name=definitely_not_a_real_file_ROOKPOC.txt'
Exploit transcript
HTTP 404 Content-Type: text/plain not found: ENOENT: no such file or directory, open '/Users/macintosh/Documents/Claude/Projects/42nights_internship/rook/fixtures/vulnerable-app/public/definitely_not_a_real_file_ROOKPOC.txt'
Confirmed: not found: ENOENT: no such file or directory, open '/Users/macintosh/Documents/Claude/Projects/42nights_internship/rook/fixtures/vulnerable-app/public/definitely_not_a_real_file_ROOKPOC.txt'
CVSS v3.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N→ 5.3 (medium)Recommended fix
AI-suggested fix — review before applying (derived from analysis of untrusted repo content):
Return a generic message and log details server-side:
--- a/server.js
+++ b/server.js
@@
- fs.readFile(path.join(__dirname, "public", name), "utf8", (err, data) => {
- if (err) return send(res, 404, `not found: ${err.message}`);
+ fs.readFile(path.join(__dirname, "public", name), "utf8", (err, data) => {
+ if (err) {
+ console.error("file read failed:", err);
+ return send(res, 404, "not found");
+ }Ship the fix
Rook found it and proved it. Hand the finding — with its working exploit as a failing test — to Otis to write the fix PR.