The bug
Here's a login endpoint from a small Express demo app
(scan-target-demo-apps/apps/01-sql-injection):
app.post('/login', (req, res) => {
const { username = '', password = '' } = req.body;
const query = `SELECT id, username, email, is_admin FROM users
WHERE username = '${username}' AND password = '${password}'`;
const result = db.exec(query);
// ...
});
You've seen this shape before. username and password go straight into the SQL string — no
parameter binding, no escaping. Submit admin' -- as the username and anything as the password,
and the query becomes:
SELECT id, username, email, is_admin FROM users
WHERE username = 'admin' -- ' AND password = 'anything'
-- comments out the rest of the line. The password check never runs. {"ok": true}, logged in
as admin.
Classic CWE-89, OWASP A03:2021. Nothing novel here — the interesting part is what caught it.
What actually caught it
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 — everything you're about to read
happened on a laptop with no network access to anywhere but localhost:3001.
The important design decision: the LLM never sees raw source code or raw HTTP traffic.
The pipeline looks like this:
Parser → Rule Engine → Knowledge Retrieval → Summarization → LLM → Reasoning → Finding → Report
A deterministic parser and rule engine do the actual finding. The local LLM only explains
already-discovered evidence — it's not asked to eyeball a codebase and guess where the bugs
might be. If the evidence isn't there, the platform is built to say "Needs Manual Verification"
instead of inventing a conclusion.
For this run, that meant:
- Point the scanner at
http://localhost:3001as scope. - Let it run a real passive crawl — no exploitation, just discovery.
- Run a source scan against the target's own directory.
- The rule engine flags the string-concatenated query pattern in
server.js:56and the missing auth check on the state-changingPOST /loginroute.
The generated report includes the actual vulnerable line as evidence, not a generic "possible SQL
injection" label:
Source preview.
app.post('/login', (req, res) => {
const { username = '', password = '' } = req.body;
const query = `SELECT id, username, email, is_admin FROM users WHERE username = '${username}' AND password = '${password}'`;
Risk: High. Root cause: CWE-89 (and a separate CWE-306 finding for the missing authorization
check). Suggested fix: parameterized queries. Confidence explicitly marked — some findings from
this pass are "Confirmed," others are flagged "Needs Manual Verification" rather than asserted,
because header/config-level evidence alone doesn't prove exploitability the way a manual
Active Test / Repeater run does.
Why "offline" is the actual point
It's easy to gloss over "runs locally" as a checkbox feature. In practice it means:
- You can point it at unreleased/internal code without a vendor's cloud pipeline ever touching it.
- The rule engine — not the LLM — does secret detection, JWT/header/cookie analysis, and pattern matching, so results are reproducible and don't drift between runs.
- The LLM's job shrinks to something it's actually reliable at: turning structured findings into a clear explanation, not hunting for vulnerabilities in raw text.
Try it yourself
The demo app is intentionally vulnerable and open source — safe to point any scanner at, including
this one:
- Demo target: https://github.com/sendwavehub/scan-target-demo-apps
- AI Security Studio: https://apps.microsoft.com/store/detail/9PJ0J7BK1M27?cid=DevShareMCLPCB
Built for security researchers, pentesters, and AppSec teams doing work they're authorized to do.
Next up in this series: stored XSS — one comment field, every visitor who loads the page.
Top comments (1)
Offline scanning is underrated for security workflows because it changes the adoption story. Teams can inspect the finding without first accepting a cloud trust boundary. The next useful layer is evidence quality: exact source path, tainted input path, and a minimal repro that a human can verify quickly.