AIToday

getdebug 0.4.0 adds Python AI-app security patterns, outperforms generic SAST tools

Hacker News14h ago
getdebug 0.4.0 adds Python AI-app security patterns, outperforms generic SAST tools

Key takeaway

getdebug released version 0.4.0 with Python-specific AI-app security detection using deterministic regex patterns, at no cost and with zero latency. In a benchmark comparing it to Bandit, Semgrep, and vulnhuntr on real-world Python code, getdebug found six AI-app-specific security issues while competing tools either generated thousands of false positives or found nothing relevant to LLM-calling applications. The tool is designed for Python apps that call LLMs—chat wrappers, agents, tool-calling backends—and complements rather than replaces general-purpose security linters.

Summaries like this, in your inbox every morning.

Sign up free →

3 Key Points

  • What happened

    getdebug CLI 0.4.0 released Python regex-based prefilters for five AI-app anti-patterns (prompt-injection, unsafe-role-merge, pii-in-prompt, unbounded-stream, unsafe-tool-output) alongside existing JS/TS detection. The tool runs deterministically with no LLM call, in milliseconds, at zero cost.

  • Why it matters

    In a benchmark against Bandit, Semgrep, and vulnhuntr on real code (Simon Willison's 49-file llm CLI), getdebug surfaced 6 AI-app-specific findings while Bandit returned 1,228 noise alerts (mostly assert_used warnings on pytest) and Semgrep found 3 generic hits with no AI-app coverage. Vulnhuntr selected zero files because it targets web-app entry points, not CLIs. For teams shipping Python apps that call LLMs, getdebug fills a gap the general-purpose security tools don't address.

  • What to watch

    getdebug also offers optional local-LLM SAST via Ollama (free, on-device) and hosted Claude-based scanning (paid). A newer version (0.5.5) introduced a stricter detector that now flags one previously-safe fixture as a critical issue, signaling the tool is still tightening its allowlist logic. Benchmark corpus and methodology are open on GitHub (CodeSecBench) and at getdebug.dev/bench; PRs welcome.

In Depth

getdebug, a CLI tool for scanning AI-app codebases, released version 0.4.0 with Python support for five deterministic, regex-based anti-pattern detectors: prompt-injection, unsafe-role-merge, pii-in-prompt, unbounded-stream, and unsafe-tool-output. These patterns join the JS/TS detectors shipped in 0.3.0. The tool runs in milliseconds, costs zero, and requires no LLM call—just static pattern matching against SDK idioms like subprocess.run(tool_call.input.command, shell=True) or stream=True without timeout guards.

The team benchmarked getdebug against three competitors: Bandit (the Python-OSS security linter standard, hand-written rules, Python-only), Semgrep (multi-language SAST with community rule packs, hand-written rules), and vulnhuntr (Protect AI's open-source LLM-app static analyzer, LLM-driven, Python-only, entry-point-detection-based). In a synthetic test on ten paired vulnerable/safe Python fixtures (one pair per anti-pattern category), getdebug achieved 83% precision and 100% recall (5 true positives, 1 false positive, 0 false negatives). Bandit and Semgrep both scored 50% precision and 20% recall (1 TP, 1 FP, 4 FN each), because they flagged the safe variant of the unsafe-tool-output fixture—one where subprocess.run(shell=True) received a value from a static allowlist, not model output. Neither tool understood that cmd came from a static dict; getdebug's regex requirement that tool_call.input.X appear in the sink argument filtered out that false positive. Both tools also missed the other four behavioural categories entirely; their rule packs contain no patterns for prompt-injection, pii-in-prompt, unsafe-role-merge, or unbounded-stream.

The real-world test ran all three working tools on simonw/llm (Simon Willison's CLI for talking to LLMs, 49 Python files, commit 0d593ea). Bandit returned 1,261 findings—1,228 of them flagged assert_used on pytest assertions, a long-standing complaint about Bandit's default config. The remaining signal was zero AI-app coverage. Semgrep found 3 generic-SAST hits (an exec() in cli.py for the plugin system, a missing-integrity attribute on a static HTML asset, a non-literal import)—again, zero AI-app specific. getdebug surfaced 7 findings: 6 AI-app categorized (1 prompt-injection from template-feature concatenation, 5 unbounded-stream hits in the OpenAI plugin with stream=True and no timeout in scope) and 1 borderline role-merge (the role echoing the API's own response, not request input). All were flagged HIGH / MEDIUM (not CRITICAL) with context to triage. vulnhuntr installed cleanly on Python 3.11 but selected zero files because its entry-point heuristic targets network-exposed web apps, not CLI tools.

The team acknowledged the earlier version (0.4.0) showed a clean sweep on the synthetic fixture, but an updated detector added in 0.5.5 (scanPyShellToolArg) now flags that safe allowlist case as CRITICAL because it sees tool_call.input.tag reaching shell=True without understanding the static routing. This regression is tracked for tightening. The authors recommend running all three tool categories complementarily: Bandit for Python hygiene (with assert_used disabled), Semgrep for cross-language SAST, and getdebug for AI-app behavioural patterns. The benchmark corpus, methodology, and harness are open on GitHub under CodeSecBench, and the tool can be installed via npm (@getdebug/cli@0.4.0) or Homebrew (getdebug-ai/tap/getdebug).

Context & Analysis

getdebug is addressing a genuine blind spot in the open-source security-linting landscape. Bandit and Semgrep are mature, widely-used tools designed for general Python security and cross-language SAST respectively; they excel at catching SQL injection, unsafe deserialization, and missing integrity checks. But neither was built to understand LLM-specific risks—serializing user objects into prompts, streaming without timeouts, merging incompatible role fields in message arrays. The benchmark reveals the cost of that generality: Bandit's 1,228 assert_used warnings on a 49-file codebase are noise for most production environments, and Semgrep's three findings are real but generic, not AI-app specific.

vulnhuntr, positioned as the category leader for LLM-driven AI-app analysis, takes a different approach by invoking an LLM to infer entry points and vulnerabilities. The tradeoff is scope: it selects files based on web-app heuristics, leaving CLI tools unanalyzed. getdebug's regex-based layer sidesteps that by running on any Python that touches an LLM SDK, whether web or command-line. The trade-off in the other direction is that hand-written regex patterns can miss novel attack surfaces that an LLM might infer; the tool's designers acknowledge this and invite open community feedback.

The public benchmark methodology and open-source corpus (CodeSecBench on GitHub) set a high bar for transparency. In the real-world test on simonw/llm, getdebug's seven findings included two that depend on threat model (prompt-injection between two CLI-user inputs in a single-user tool) and role-merge logic routed through API responses rather than request input. The tool surfaces everything flagged, lets teams triage via .getdebug-ignore files, and acknowledges the borderline cases—a stance that trades off noise reduction for completeness.

FAQ

How does getdebug detect AI-app vulnerabilities without calling an LLM?
getdebug 0.4.0 uses deterministic regex patterns that match SDK idioms—for example, it looks for tool_call.input.X references reaching a shell=True sink in subprocess.run(), or messages arrays with system-role prompts containing user-supplied variables. These patterns require zero LLM calls and run in milliseconds at no cost.
Why did vulnhuntr find nothing on the test repo?
vulnhuntr's file-selection heuristic targets network-exposed entry points (web apps), not CLIs. Since simonw/llm is a command-line tool, vulnhuntr selected zero files to analyze. It is not broken—just scoped to a different target than getdebug, which runs on any Python touching an LLM.
What does getdebug catch that Bandit and Semgrep don't?
Bandit and Semgrep both fired on a safe pattern where subprocess.run(shell=True) was called on an allowlisted value, not model output. getdebug's regex requires the tool_call.input.X reference to appear in the sink argument, avoiding that false positive. Both tools also miss four behavioural categories entirely: pii-in-prompt, unsafe-role-merge, prompt-injection, and unbounded-stream—patterns specific to LLM-calling apps.

Get the latest AI Coding Assistants news every morning

AI-summarized, only the topics you pick — one digest a day via Email, Slack, or Discord.

Free · takes 30 seconds · unsubscribe anytime

Discussion

No comments yet. Be the first to share your thoughts!

Log in to join the discussion

Related Articles

Stay ahead with AI news

Get curated AI news from 200+ sources delivered daily to your inbox. Free to use.

Get Started Free

Free · takes 30 seconds · unsubscribe anytime