The autonomous AI pentester that proves every exploit.
Basilisk is an open-source autonomous penetration-testing agent — a native Linux desktop app that hands a language model a real shell and a real methodology, then gets out of the way.
87 of 113 on OWASP Juice Shop. Black-box, fully autonomous, no source on the machine. The leading commercial agent scores 49 on that board with your source code in its hands — and 36 without. Basilisk beats its white-box run blind, by 38 challenges, on one of the cheapest models on the market. Then 22 of 22 on Escape's Duck Store API, a target no model has memorised. MIT — free to own, free to run.
It did all of that driving DeepSeek-V4-Flash, one of the cheapest models on the market. Read that twice: the scaffolding scores, not the price tag.
Your machine. Your key. Your data. MIT-licensed, no account, nothing phoning home. It doesn't guess. It confirms.
Why it beats bare models. Most autonomous "AI pentesters" ask the model whether the bug worked and write down the answer. That is a confidence score wearing a lab coat, and it is why their findings drift and their numbers fall apart on targets the model has never seen. Basilisk arms every exploit with the thing that would prove it — a dumped row, another user's token, an out-of-band callback — fires, and checks for that marker before anything is recorded. No proof, no finding. That one rule is the whole difference.
Basilisk executes real exploits and real shell commands against whatever you point it at, on its own, with your user's privileges. In Unleash mode it confirms the target, then runs with no per-step approval and does not stop until the objective is met.
Aimed at the wrong host, it will keep working that host until you pull it off. Run it only against systems you own or have explicit written authorization to test — unauthorized testing is a crime in most jurisdictions.
The irreversible-command class — disk wipes, recursive root deletes, fork bombs, raw block-device writes — is hard-blocked in two independent places, below the model, with no "run anyway". That floor protects your machine. Nothing in the tool protects you from pointing it at someone else's.
A GTK4 desktop app that gives a language model hands.
Point it at a target you're authorized to test and it runs the engagement end to end: recon, exploitation across every web-vulnerability class, verification, write-up. Turn after turn, on its own, until the objective is confirmed or you press Stop.
One tap of Unleash and it says the target out loud, then works it off the leash — no per-step approval, no babysitting, no stopping until the mission is verifiably done. Errors don't end the run. It reads them and keeps going.
Then it does the job in reverse. Hand it a zip of your own repository and it edits the tree, runs your tests, and hands back a zip that passes them. Same loop both times: do the thing, then prove it worked. It also audits code across ten scanners, hardens a host, and drives your shell and desktop.
The claim is only worth the number you can regenerate.
Scored against OWASP Juice Shop, which marks a challenge solved only when the exploit actually fires. No partial credit. No checklist to recall. Graded one to six stars by difficulty — and it's the board the security community already argues over, which is exactly why it's the one worth posting.
The curve is the honest part. It clears the entire lower half outright — every one- and two-star, and 24 of 26 three-star — then thins as the chains get deeper. That is the shape a real tool has; a suspiciously flat one usually means the model recognised the target rather than exploited it.
At the deep end it still takes 13 of 19 five-star and 7 of 12 six-star, including SSRF, SSTi, Forged Signed JWT and Arbitrary File Write. The misses cluster in one honest place: where a single builder isn't enough and the chain runs long — RCE/DoS variants, NoSQL manipulation, and the LLM-chatbot challenges. Those are the next target, and they're listed here rather than rounded away.
| Agent | Licence | Black-box | White-box (source given) |
|---|---|---|---|
| Priest's Basilisk v7.6.0 | MIT · free | 87 / 113 | — |
| Priest's Basilisk v7.5.3 | MIT · free | 81 / 113 | — |
| Priest's Basilisk v7.1.0 | MIT · free | 73 / 113 | — |
| Priest's Basilisk v6.0.0 | MIT · free | 58 / 113 | — |
| Cascade (Windsurf / Escape) | commercial · quote-only | 36 / 113 | 49 / 113 |
| Claude Opus 4.8 (bare model) | metered API | 23 / 113 | 24 / 113 |
Published work generally puts fully-autonomous LLM pentest agents around 20–30% on comparable tasks. Basilisk clears roughly 77% on the full board, black-box — well above that line, and on one of the cheapest models on the market at that.
Read the two right-hand columns together. Cascade's best number — 49 / 113 — is its white-box run: it was handed the source code. Basilisk's 87 / 113 is black-box, with no source on the machine, the way a real engagement actually starts.
That is 1.8× its white-box score, blind — 38 more challenges. Scored like for like, black-box against black-box, it is 2.4× Cascade (+51) and 3.8× a bare frontier model.
Every number here was produced driving DeepSeek-V4-Flash — a cheap, fast model, not a frontier one — against a commercial product running frontier models. The result isn't the model, it's the verified-exploitation loop wrapped around it: hypothesis → deterministic exploit builder → fire → prove it against ground truth → keep the receipt.
One of these you buy through a sales conversation. The other is MIT, and you can clone it in the next ten seconds.
Escape's Duck Store — a deliberately-vulnerable REST API.
A different shape of target from Juice Shop: the planted flaws are API-first — broken object- and function-level authorization, mass-assignment privilege escalation, server-side request forgery, and business-logic abuse. Basilisk found every one working purely from the live API surface, no schema handed to it.
Don't take the number. Regenerate it.
Stand up the same container, point Basilisk at the board, and call juiceshop_report — it reads the live scoreboard at /api/Challenges and reports solved and available by difficulty. Score any other tool against the same container and compare.
# spin up the graded target, then aim Basilisk at it
docker run -d -p 3000:3000 -e NODE_ENV=unsafe \
--name juiceshop bkimminich/juice-shop
A closed loop, not a payload spray.
Basilisk reads a target's behaviour to identify the vulnerability class, reaches for the matching exploit builder, fires it, and confirms the hit against ground truth before moving on. Every attempt and verdict lands in an exploitation oracle — so the loop never re-runs a solved bug and gets sharper about what's left.
In plain English: a scanner throws payloads at a page and reports what looked odd. Basilisk decides what would have to be true if the bug were real — a specific row appearing, a specific token leaking, a callback arriving at a server only it knows about — then goes and checks whether that actually happened. It is the difference between "this smells like SQL injection" and "here is a row out of your database."
Read the behaviour
Fingerprint the stack and watch how the target responds — reflections, timing, error shapes — to name the vulnerability class.
Match a builder
Reach for the general-purpose exploit generator for that class, parameterised for this target — not a Juice-Shop-bound toy.
Arm the proof
Bind the marker that would prove the bug: a dumped row, a foreign token, a status, a measurable difference, an OOB callback.
Fire
Send the payload through the same gate every command passes — with the destructive class hard-blocked underneath it.
Check ground truth
Look for the armed marker in the response. A 200 or a plausible-looking body is not a solve; only the marker is.
Record the verdict
Write confirmed / failed / pending into a ledger it consults every planning turn, hashing the command as it goes.
Exploit builders
Four subsystems bridge a CTF and a real host
Parses a JSON or XML body, injects at every node, and serialises back to valid syntax — so the payload actually reaches each field instead of breaking the parser.
Extracts every dynamic token from a response — cookies, CSRF, bearer/JWT, nonces — and threads it into the next request, reaching steps a stateless scanner never gets to.
Proves blind bugs by measuring: diffs TRUE vs FALSE responses for a boolean channel, and analyses latency statistically (mean, stddev, z-score) to confirm time-based blind past network jitter.
Arms, fires, and checks — recording confirmed / failed / pending in a ledger. For blind bugs that echo nothing back it stands up a local out-of-band canary listener: the payload carries a unique callback URL, and a hit proves the bug with certainty. Runs locally and offline.
The same discipline, pointed at your own code.
Hand Basilisk a .zip of your repository and it works the whole tree: searches it, reads it, edits it, runs your tests, hands back a zip that passes them. Same loop as the engagement, pointed the other way. No passing test, no fix — and it will not touch your tests to get one.
Baseline before it touches anything
It runs your tests first and records what was already red. Without that, every pre-existing failure looks like agent damage — and worse, an already-broken test gets quietly "fixed" and folded into a diff you never asked for and can't separate from your own work.
It tracks failing test names, not counts
A count can't tell "fixed one, broke another" apart from "nothing changed" — both read as two failed. So the verdict is computed from the failure set, and broke is the first thing it reports.
It won't export work it hasn't verified
Export is the one moment your real repository is at risk, and "the model said it was fine" is not evidence. Unverified edits, or a last run that reported a regression, and the export is refused. You can force it — but you have to ask, and the result is flagged.
Your archive is untrusted input
This is the one thing that takes a file from outside and writes it under a name the file chooses. Zip slip, symlink entries and zip bombs are refused before anything is written — and refusals are reported, not silently dropped, so you never think the import just lost data. A stray .env is flagged and kept out of the model's context.
And the rule it will not break: it does not touch your tests to make them pass. Editing a test to match broken code is the single worst thing an agent can do in a repository, so it is prohibited in the persona and the verdict is computed from your suite, not its opinion of its own work.
It remembers, it learns, and it writes its own tools.
Basilisk is not a stateless prompt. It carries persistent memory across sessions, sharpens itself inside an engagement, and can extend its own toolset when something is missing — all on your machine, all under your control.
Persistent memory across sessions
Facts, preferences, past fixes, and prior findings persist in a local SQLite store you own. Recall is relevance-scoped: each turn pulls only the handful of memories most relevant to the current task, so history can grow indefinitely without ever bloating the context window or the token bill. It's keyword-based by default — zero model compute, fast enough to run on a phone — and upgrades to embedding similarity when a model provides it. One settings toggle, one memory_forget tool, and nothing leaves the box.
Learns within the engagement
Every attempt and verdict lands in the exploitation oracle. Confirmed bugs are never re-run and dead ends aren't retried, so the longer Basilisk works a target the sharper its next move gets — it spends its turns on what isn't proven yet. When an approach stalls, it pulls the exact technique from a vetted source and applies it on the following move instead of flailing.
Writes and keeps its own tools
When the toolbox is missing something, Basilisk can write a new Python tool, test it, and keep it — but only if it passes. A proposed skill runs nothing until you click Apply; then it's parsed, run against its own test in the sandbox, and saved only if that test succeeds. A tool that can't prove it works is never kept. Every later call runs in the sandbox too, and unused skills are archived rather than deleted.
Remove the doors rather than bolt on a filter.
An agent that reads the outside world and runs shell commands is a prompt-injection target by construction. So the design assumption is that the model is already compromised — and the things that matter are put where a compromised model cannot reach them. Not filtered. Removed.
Injection surface removed, then gated
Tools that fetched attacker-chosen URLs are gone. What's left reads only from a fixed allow-list, split in code: trusted advisories (NVD, MITRE, CISA) fetch automatically; user-authored sources (GitHub, exploit-db) are held outside the loop behind a one-tap approval. Off-list URLs, redirects, and cloud-metadata addresses are refused.
The irreversible class can't run — twice
A structural detector hard-blocks disk wipes, recursive root/$HOME deletes, fork bombs, and raw block-device writes. It judges the command that will actually run, not the word that comes first — peeling wrappers and their own options (timeout 5 …, nice -n 5 …, sudo -u root …), reading through ( … ), { …; } and if/then, and entering sh -c, eval, trap, xargs and command substitutions. Refused at the UI gate and inside the execution primitive. There is no "Run anyway."
Untrusted input is quarantined
Anything from outside — a target's response, an MCP result, an analysed image — passes a deterministic content firewall and is wrapped as data, never instructions before the model ever sees it.
Your sudo password never touches the model
When a command needs root, Basilisk asks you. The password reaches sudo through an askpass helper — never into the prompt, never onto disk, never into a log, and never into the process argument list where any user on the box could read it with ps.
It cannot edit its own safety code
A command that would write to, truncate, redirect into, sed -i or copy over the safety and scope modules is refused — including when the write hides inside sh -c, an interpreter one-liner, or a cp destination. The immutable guardrail block is hash-verified byte-for-byte every release.
Self-written tools run jailed, and only if they pass
When the toolbox falls short, Basilisk writes a new Python tool and a test for it. The code is AST-parsed, statically screened, and run against that test inside a bubblewrap sandbox — and kept only if it passes. A tool that can't prove it works is discarded, not saved with a warning. Every later call runs jailed too.
Scope is a boundary, not a suggestion
Before any active command runs, its targets are extracted and checked against the list you authorised. It fails closed: no scope set, an unparseable command, or no match all mean refused. It reads through sh -c, wrapper prefixes and command substitution — the same shapes the destructive floor handles.
Your provider stays where you put it
Basilisk never quietly hops to a different cloud. The provider you pick is pinned, and a retry after a degraded reply goes back to the same one — so your engagement data never lands somewhere you didn't choose. It won't build standalone weaponised malware either: no reverse shells, implants, ransomware or backdoors. That line lives in the immutable guardrail, not a swappable prompt.
In plain English: the model is treated like a talented contractor with a key to one room. It can do anything inside that room, including things that would wreck the room. It cannot get out of it, cannot change the locks, cannot read your wallet on the way past, and cannot take the tools home.
Claims are cheap. Run the suite.
Every claim on this page is either a number you can regenerate or a test you can run. The suite is stdlib-only — no pytest, no network, no fixtures, no account, nothing to install — and it finishes in under a minute on a laptop. You do not have to believe any of this. You can check it.
for f in tests/test_*.py; do python3 "$f" || echo "RED $f"; done
Bugs are pinned, not described
When a real bug is fixed, the test that catches it is written to fail against the previous release. A regression cannot quietly return — it has to walk back past a test that was built from the bug itself.
Performance is asserted as a shape
A millisecond ceiling passes by luck on a fast machine. So the suite also asserts the scaling exponent — quadruple the input, the time must not quadruple. That fails identically on a fast box and a slow one.
Counter-properties, tested as hard
Every safety check is paired with a corpus of ordinary work it must stay silent on. Over-blocking fails the suite too — a safety feature people switch off protects nothing at all.
The shipped artifact is what's verified
The release archive is extracted fresh and the full suite run from inside it — not from the working tree it was built in. The guardrail block is hash-checked every release; the safety, scope and ledger modules are diffed byte-for-byte.
We fuzz our own safety floor, and publish what it finds.
The hard block on irreversible commands is the one piece of Basilisk that has to be right, because under Unleash nobody is on the trigger. So we attack it on purpose, every release, and publish whatever it gives up.
v9.7.0 · twenty-one shapes closed
The gate was fuzzed against a live shell — every candidate bypass re-run in real bash with the destructive verb swapped for a harmless marker, counting only the shapes where the shell actually did the thing. Twenty-one that had been getting through were found and closed, among them timeout 5 rm -rf /, ( rm -rf ~ ) and $(rm -rf /).
The method mattered more than the fixes
A blind fuzz reported 18,856 "bypasses" — nearly all of them shell syntax errors that never execute and never mattered. Filtering down to what a real shell genuinely runs is what made the twenty-one findable at all. They are now pinned by a suite that fails against the previous release.
Said plainly: those bypasses were real, not theoretical. timeout 5 rm -rf / is not an attack — it is something a model writes by accident. The honest claim is not that Basilisk has never had a hole; it is that the holes get hunted, published, and pinned. If you find a twenty-second shape, open an issue. That is the arrangement.
You supply the brain. Keys stay on your disk.
Bring one key for whichever provider you want, set in Settings → Backends. It lives in ~/.config/basilisk/settings.json, locked to your user, and goes nowhere except that provider's own API. There is no Basilisk account to make, because there is no Basilisk server to make it on.
Large open models — DeepSeek, Qwen, Kimi — plus SenseVoice speech-to-text.
Get a key →Read the installer. Then run it.
Basilisk runs shell commands as you. So it ships as plain Python and one shell script you can read start to finish before you run it — which you should, and which is the point of it being one file. The installer detects your distro, parse-checks every file before it touches disk, and backs up your chat history. The same command updates in place.
curl -fsSL https://raw.githubusercontent.com/the-priest/PriestsBasilisk/main/install.sh | bash
git clone https://github.com/the-priest/PriestsBasilisk.git basilisk
cd basilisk
less install.sh # read it first
./install.sh
- Python 3.10+, Linux with GTK4 / libadwaita (X11 or Wayland).
- Built and tested on Kali and CachyOS; package manager, escalation tool and wordlist paths are auto-detected on any Arch/Debian/Fedora base.
- Standard tooling (nmap, sqlmap, …) is auto-detected; missing tools are flagged with an install hint, never assumed.
What it is not, and what it can't do.
Every tool page lists strengths. Here are the limits, because you will find them anyway and it is better you hear them from us.
It is not a replacement for a pentester
It is an extremely fast, tireless pair of hands that never skips the boring half of the methodology. Scoping the engagement, judging business impact, deciding what a finding is worth, and writing the part of the report a client acts on — still yours.
It gets weaker as the chain gets longer
Look at the difficulty curve above: near-total at one to three stars, thinning in the deep end. Bugs needing four unrelated insights stacked in the right order are still where autonomous agents lose. The misses are published by name rather than rounded away.
It is only as good as the model you give it
The scaffolding is what scores — that is the whole thesis — but a weak model still reasons weakly inside it. The benchmarks were run on a cheap model on purpose. They were not run on every model.
The benchmark numbers are ours
They are reproducible — exact target, flags, model and scoreboard commands are published so you can re-run them — but they are self-reported. Treat them the way you would treat any vendor's self-reported number until you have regenerated one yourself.
Linux and GTK4 only
No Windows, no macOS. It is built and tested on Kali and CachyOS, and it does not run on your work laptop's default OS.
The model call still leaves your machine
Everything else is local — your findings, ledger and history sit in SQLite on your disk. But the API call to your chosen provider goes out. If your engagement data cannot touch a third-party API, this is the wrong tool until you point it at something self-hosted.
And the one that matters most: the floors are real, tested, and they stop Basilisk destroying your machine. Nothing in the software stops you aiming it at a host you have no right to touch — and it will keep working that host until you pull it off. That part was never a software problem.
Straight answers.
Common questions about Basilisk as an AI penetration-testing agent — how it compares, what it runs on, and whether it's safe.