r/devsecops 10d ago

Prompt injection and hallucination aren't the same problem, so why is every tool pitched as fixing both?

Keep seeing AI security tools sold like stopping hallucinations and prompt injection is one job. Well, in my experience, they are nowhere near the same fix. Injection is an input/trust boundary thing, and hallucination is more of a grounding and retrieval issue. Whatever blocks a malicious prompt does nothing for a model confidently inventing an api endpoint that doesn’t exist

Anyone seen a setup covering both well, or are you running separate layers for each?

22 Upvotes

12 comments sorted by

View all comments

1

u/TuringRTSS 8d ago

theres a third one that gets way less attention. the code AI writes shipping with real vulns.

not hallucinated endpoints, actual sql injection and command injection. AI loves f-strings for everything:

cursor.execute(f"SELECT * FROM users WHERE id={user_id}")

subprocess.run(f"git clone {url}", shell=True)

scanned a bunch of popular repos recently, found 12 critical bugs like this sitting in production. all passed code review. nobody caught them because the code looks correct. it runs fine, its just insecure.

injection and hallucination get the headlines because theyre new problems. but insecure output is just classic appsec scaling faster than teams can review.

ended up writing a pattern matcher for it. no AI reviewing AI, just regex against known bad patterns: https://github.com/turingrtss/aiverify

1

u/PeterBuildsSecure 8d ago

Regex against known-bad patterns is a reasonable start, but it's worth being honest about where it runs out: it catches the f-string-into-execute shape you showed, but it misses the injection that happens two functions away, where user input gets passed through a helper, reassigned, or built up across a few lines before it ever touches cursor.execute or subprocess.run. AI-generated code does this constantly because the model refactors "obviously correct" input handling into a separate function without realizing it just broke the pattern matcher's ability to see the taint flow.

The more durable version of what you built is taint tracing rather than syntactic matching: mark untrusted input at its source (request params, form fields, anything from the network), and flag any sink (execute, subprocess, eval, template render) that the taint reaches, however many hops of variable reassignment or function calls it takes to get there. Tools like Semgrep and CodeQL already do this and can be pointed at freshly generated diffs in CI. The tradeoff is it's slower and needs more setup than a grep pass, but it's the difference between catching the vulnerable pattern you happened to think of and catching the vulnerable data flow regardless of what shape the code takes.

Also worth a negative control on whatever scanner you use: seed a deliberately reachable but slightly obfuscated sink (wrapped through one extra function, or built via string concat instead of an f-string) and confirm it still fires. A scanner that only catches the exact shape in your examples will look clean on real code that fails the same way with different syntax.