Inspiration
Manual pentesting is slow because a human has to manually chain a dozen different tools (Nmap, Nuclei, sqlmap, Metasploit) by hand — run one, read its raw output, decide the next step, repeat. The tools aren't the bottleneck, the manual chaining between them is. Wanted to test whether an LLM ReAct loop could actually drive that chain end-to-end against a real target, while keeping a human as the only one who can authorize anything that actually acts on the target.
What it does
Point ASRA at an authorized target (or several) through a web UI. It runs a 4-phase ReAct loop:
- Recon — Nmap, subdomain enum (crt.sh/Wayback), DNS/WHOIS, CVE lookup. Records every target the instant it's found.
- Analyze — Nuclei plus native checks (security headers, exposed paths, fingerprinting, deterministic SQLi/XSS/open-redirect/command-injection detectors). Records every finding the instant it's found.
- Exploit — verifies a finding, then runs exactly one real exploitation attempt (Metasploit / sqlmap / default-creds check) — only against a target on an explicit allowlist, and only after a human clicks "approve" for that session.
- Validate — one final LLM pass deduplicates overlapping findings.
Everything streams live to the browser (SSE), an operator can chat with a running scan (add guidance, skip a finding, jump to a deep-dive), an interrupted session resumes instead of restarting, and a completed session exports a standalone HTML proof report. LLM backend is swappable — opencode-zen (free default) or Qwen (Alibaba DashScope) out of the box, any other OpenAI-compatible provider is a one-line config addition.
How we built it
- Python, FastAPI + Jinja2/HTMX for the web layer, plain JSON files as session storage — no database.
agent/core.py— the ReAct orchestrator. Stall-detection (same tool call repeated N times in a row ends a phase) instead of a fixed step-count cap, so a large scan scope never gets cut off early. One corrective retry per failed tool call before giving up on it.agent/llm_client.py— one OpenAI-compatible client behind every provider. Resolution order: explicit override → saved UI setting →.env→ hardcoded default. Auto-detects native vs. prompt-based tool-calling per model and falls back at runtime if the provider rejects native calls.agent/tools/— category-based registry (recon/scan/exploit). Built-in tools (Nmap, Nuclei, Metasploit, sqlmap) plus automatic discovery of anything already onPATH(subfinder, ffuf, nikto, hydra...) plus user-defined tools viacustom_tools.yaml— adding a tool never means touching the orchestrator.agent/tools/runner.py— the single chokepoint every tool call passes through: allowlist check, binary health-check, timeout, then dispatch. This is where safety is enforced, not in a prompt instruction the model could ignore.- Runs locally: Windows via WSL2 (any distro — package manager auto-detected: apt/dnf/pacman),
Linux/macOS natively. One script (
setup_tools.sh) installs the 5 core security tools, idempotent and safe to re-run.
Challenges we ran into
- Stopping the agent loop reliably without an arbitrary step cap — a fixed budget cuts off a large scan scope before it's actually stuck. Solved with stall-detection instead: only an identical tool call repeated back-to-back ends a phase.
- LLM providers disagree on native function-calling support — built capability detection (models.dev catalog) plus a runtime fallback to prompt-based tool-calling if a provider rejects the native call format mid-session.
- Packaging for Windows without native support: the security tools are Linux-only, so Windows runs
through WSL2. On top of that, Git for Windows' default
core.autocrlf=truesilently corrupts shell scripts to CRLF, and the executable bit isn't preserved on an NTFS-hosted repo — both would break a fresh clone. Fixed with.gitattributesforcing LF on.shfiles and invoking scripts asbash run.shinstead of relying on./run.sh. - Allowing real exploitation without making it unsafe — solved with two independent gates: an allowlist that's empty until a target is explicitly authorized, and a per-session human approval click, both enforced in the tool runner itself.
- Session state surviving a crash mid-scan — every finding/log is persisted the moment it's produced instead of batched at the end of a phase, so an interrupted run resumes instead of losing everything already found.
Accomplishments that we're proud of
- The full four-phase pipeline runs end-to-end against real, intentionally vulnerable public targets — recon through actual exploitation with evidence, not a scripted/mocked demo.
- The human-in-the-loop gate is enforced in code (tool runner), not just a prompt instruction the model could talk itself out of.
- Swapping the LLM provider (opencode-zen → Qwen or any other OpenAI-compatible endpoint) is a one-line config change, zero code changes.
- The tool registry grows on its own: anything already installed on
PATHgets auto-discovered, no hardcoded tool list to maintain as the arsenal grows. - Setup is one script per platform (
setup_tools.shfor WSL2/Linux), idempotent — safe to re-run on a machine that already has some tools installed.
What we learned
- An LLM can reliably drive a real multi-tool operational loop given structured tool results and a clear stop condition — but destructive actions still need deterministic guardrails (allowlist, approval, timeouts) around them; the prompt alone isn't a safety boundary.
- Stall/repeat detection generalizes better than a fixed step-count cap for an agent loop whose workload size isn't known ahead of time (one host vs. a wide scope).
- Packaging a Linux-tool-dependent agent for a Windows audience is mostly a WSL2/Git line-ending and permissions problem, not an agent-logic problem — those caused more real, reproducible bugs than the ReAct loop itself did.
What's next for ASRA
- More detection coverage and tool integrations — the registry already supports this without
touching the orchestrator (
KNOWN_TOOLS+custom_tools.yaml). - Cross-session memory instead of every session starting from zero context.
- Verified native macOS support (currently written but not tested on physical Mac hardware).
- Parallel scanning of multiple targets within a single session.
Log in or sign up for Devpost to join the conversation.