DEV Community

Cover image for I Built an AI Security Agent That Found Vulnerabilities in Its Own Code (And Why That's the Point)
greenbladesec
greenbladesec

Posted on

I Built an AI Security Agent That Found Vulnerabilities in Its Own Code (And Why That's the Point)

I Built an AI Security Triage Tool That Found a Vulnerability in Itself

Tools called: parse_bandit, deduplicate_findings, score_findings, apply_suppressions, generate_report

Iterations: 6
Stop reason: done

Triage Summary

7 findings total

  • 🔴 Medium: 4
  • 🟡 Low: 3

Notable Findings

  • parsers/zap.py:14 — [MEDIUM] B314 — xml.etree.ElementTree.parse on untrusted XML

    • CWE-20: Improper Input Validation
    • Potential XXE vulnerability
  • core/llm.py:90 — [MEDIUM] B310 — urllib.request.urlopen with an unvalidated scheme

    • CWE-22: Path Traversal risk
  • kev/rules.py:158 — [LOW] B110 — Bare except: pass silently swallowing errors


The Finding That Got Me

The ZAP XML finding was the one that really got my attention.

My security triage tool is designed to parse scanner output. One of the scanners it supports is ZAP, which produces XML reports.

The parser was using Python's xml.etree.ElementTree to process that XML.

That parser can be unsafe when handling untrusted XML because of XXE (XML External Entity) attacks.

In other words, if someone managed to feed P1 a maliciously crafted ZAP report, the parser could potentially be abused to read arbitrary files.

The interesting part wasn't just that the tool detected the issue.

It found a real vulnerability in itself.

The agent:

  1. Parsed the scanner findings
  2. Deduplicated them
  3. Scored them
  4. Applied suppressions
  5. Generated a structured JSON report
  6. Produced a prioritized remediation list

That's the whole point.

Build the tool to automate the boring first-pass work — and then let it tell you where the actual problems are.


This Isn't Replacing Anyone

I want to be clear about what this is and isn't.

This tool doesn't replace a security engineer.

It doesn't replace DAST.
It doesn't do threat modeling.
It doesn't understand business context.

What it does is compress the boring part of the job — the mechanical first-pass triage — so a human can spend more time on the decisions that actually require judgment.

And honestly, that's one of the biggest things I learned from building it.

The automation isn't the hard part.

Understanding the security workflow is.


Building It Forced Me to Understand the Entire Pipeline

I had to understand how each scanner actually represents its findings.

For example:

  • Semgrep → JSON
  • Bandit → JSON
  • ZAP → XML
  • Trivy → JSON
  • Nuclei → JSONL

They're all different.

Then there was the question of deduplication.

What's a good deduplication key when the same vulnerability can be reported by multiple scanners?

It turns out rule_id + file + line isn't necessarily good enough because rule IDs can diverge across tools.

A better starting point is something like:

CWE + file + line
Enter fullscreen mode Exit fullscreen mode

Then there's risk scoring.

How do CWE-based heuristics translate into an actionable severity score?

And where do those heuristics break down?

Then suppressions.

How should suppressions.yaml work without becoming a mechanism for silently hiding real vulnerabilities?

And finally, the LLM layer.

What can an LLM reliably identify as a false positive?

What shouldn't it be trusted to decide?

These aren't problems you can completely shortcut by using someone else's enterprise triage platform.

You have to understand the process to know what you're automating.


Architecture

For the technical readers, here's the current architecture.

agent-core (shared library)
├── Agent
│   └── iterative tool-calling loop
│       ├── max_iterations
│       └── policy enforcement
│
├── ToolRegistry
│   └── @tool decorator → schema → LLM tool spec
│
├── ExecutionPolicy
│   ├── READ_ONLY
│   ├── SAFE
│   ├── AUTO
│   └── HUMAN_CONFIRM
│
├── LLMProvider
│   ├── ClaudeProvider
│   └── OllamaProvider
│
└── AgentTracer
    └── JSONL per-call observability


p1-sast-dast-triage
├── agent/tools.py
│   └── 10 @tool functions + session store
│
├── agent/triage_agent.py
│   └── TriageAgent
│       └── wraps agent-core.Agent
│
└── main.py
    └── existing CLI
        ├── --agentic
        └── --provider
Enter fullscreen mode Exit fullscreen mode

Key Design Decisions

1. ExecutionPolicy.SAFE

The LLM can call read-only analysis tools and write reports.

It cannot execute arbitrary shell commands.

That's an important boundary for an agent operating on security findings.

2. Session Store

Findings live in memory and are keyed by session_id.

The tools return summaries rather than dumping the entire underlying dataset into every model interaction.

This keeps the agent context smaller and makes the tool interface more predictable.

3. Backward Compatible

The existing main.py pipeline remains untouched.

The agentic functionality is additive:

--agentic
--provider
Enter fullscreen mode Exit fullscreen mode

You can use the existing deterministic pipeline or opt into the agentic workflow.


What's Next?

P1 is part of a 5-project security tooling series.

  • P1 — SAST/DAST Triage → this project
  • P2 — Threat Model Generator → done
  • P3 — AI Log Anomaly Detector → done
  • P4 — AI Pentest Report Assistant → done
  • P5 — Autonomous HTB Pipeline → in progress

Each project reuses agent-core.

The bigger goal is to build an agentic security research toolkit where tools compose.

Instead of building five completely independent AI security tools, the idea is to build reusable agent infrastructure and then compose specialized security workflows on top of it.


What I Learned

The most interesting result wasn't the number of findings.

It was the feedback loop.

I built a tool to help find vulnerabilities.

The tool found a vulnerability in the tool.

That forced me to look at the implementation from the perspective of an attacker rather than just the perspective of the person building the automation.

And that's probably the most useful property an automated security tool can have:

It should make you better at seeing the things you might otherwise miss.


Code

The projects are open source:

If you're building agentic security tooling, I'd be interested in hearing how you're handling tool permissions, false-positive filtering, deduplication, and human-in-the-loop decisions.

Top comments (0)