Path traversal caught two ways — static analysis and a live probe, no cloud AI

9
calendar_today agoschedule3 min read

The bug

Here's the route from a small Express demo app
(scan-target-demo-apps/apps/06-path-traversal):

app.get('/files', (req, res) => {
  const name = req.query.name;
  const filePath = path.join(docsDir, name);
  fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) {
      return res.status(404).json({ error: 'file not found', path: filePath });
    }
    res.type('text/plain').send(data);
  });
});

name comes straight from the query string and goes straight into path.join() — no check that the
resolved path actually stays inside docsDir. path.join('./docs', '../secret.txt') happily
resolves to a file outside ./docs. Request /files?name=../secret.txt and the server reads and
returns whatever's sitting one directory above the one it's supposed to be confined to.

Classic CWE-22, OWASP A01:2021 (Broken Access Control). Nothing novel in the bug itself — the
interesting part, again, is what caught it and how many independent ways.

What actually caught it — twice, independently

We ran this target through AI Security Studio, an offline security research platform we've been
building. No cloud calls, no code leaves the machine.

This is the first target in the series where the bug is confirmed by both ends of the pipeline
at once, not just one:

1. Static — before anyone opens the app. The same JavaScript taint rule that flags command
injection also declares a filesystem sink: fs.readFile / readFileSync / writeFile /
.sendFile(, etc. It traces req.query.namepath.join(docsDir, name)fs.readFile(filePath, …) entirely inside server.js, and auto-creates a finding — Risk: High, CWE-22, OWASP A01:2021 —
with zero manual steps. This scores reachability: untrusted input reaches a filesystem sink.

2. Dynamic — a live, automated probe. Unlike some other bug classes in this series where the
active-probe side isn't wired up yet, path traversal has a real, on-by-default probe
(PathTraversalProbeAdapter, ProbeSafetyTier.ReadOnly). Point it at /files with parameter name
and run it: it comes back with a Critical finding, Confidence: Likely, and — the part that
usually takes a human write-up — an attached, ready-to-run curl reproduction already generated. This
scores confirmed exploitation, which is why it lands at a higher risk level than the static-only
finding for the same root cause. Different numbers for the same bug at different pipeline stages is
expected, not a bug in the platform.

Proving it by hand needs nothing but a browser, too — no tooling required:

GET /files?name=../secret.txt

returns the contents of secret.txt, a file that lives one directory above the app's intended
./docs root and was never meant to be reachable through /files at all.

Why "offline" is the actual point

  • You can point this at unreleased/internal code without a vendor's cloud pipeline ever touching it.
  • The rule engine and the active-test probe — not the LLM — do the actual finding and the actual
    exploitation. Results are reproducible and don't drift between runs.
  • The local LLM's job shrinks to something it's actually reliable at: turning the already-structured
    evidence (the tainted source line, the curl proof, the CWE/OWASP references) into a plain-language
    explanation — "untrusted input reaches a filesystem read via unsanitized path.join, allowing
    arbitrary file disclosure outside the intended directory." No raw request/response bodies, no raw
    source files, ever get handed to the model directly.

Try it yourself

The demo app is intentionally vulnerable and open source — safe to point any scanner at, including
this one:

Try it yourself → https://github.com/sendwavehub/scan-target-demo-apps
Windows Store https://apps.microsoft.com/detail/9pj0j7bk1m27?hl=en-US
Web Site https://Sendwavehub.tech/en/apps/ai-security-studio-4

Built for security researchers, pentesters, and AppSec teams doing work they're authorized to do.

1 Comment

1 vote
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelski - Mar 19

The Zero-Net-Loss Fleet & The Mercenary Squad: A Live AI Economy

DEVPlank - Aug 4

Comparison: Universal Import vs. Plaid/Yodlee

Pocket Portfolio - Mar 12

MCP Is the USB-C of AI. So Why Are You Plugging Everything In?

Ken W. Algerverified - Jun 10

The Sovereign Vault — A Comprehensive Guide to Protocol-Driven AI

Ken W. Algerverified - Jun 4
chevron_left
255 Points9 Badges
Thailandjomynn.com
6Posts
1Comments

Related Jobs

View all jobs →

Commenters (This Week)

4 comments
2 comments
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!