# pwner — full site text > Every page of https://pwner.si rendered as one Markdown document, generated > from the pages themselves. For the short version see /llms.txt. Source code: > https://github.com/0x45dd/pwner — AGPL-3.0-or-later, authorized use only. --- # Home https://pwner.si/ ## An agentic network pentest tool you talk to. Open a terminal session and chat with an agent that discovers hosts, fingerprints services, checks for known issues and — when you approve — exploits them to prove impact. It runs on your own model or a deterministic fallback, stays locked to the scope you set, and asks before anything intrusive. Your model, your machine. ``` curl -fsSL pwner.si/install.sh | bash ``` macOS and Linux. Builds its own virtualenv, leaves your system Python alone, and puts pwner on your PATH. Read the script · other ways to install Sample session, fictional lab (10.0.0.0/24). Agent wording and counts are illustrative. The network panel is the live map the agent builds as it goes, hosts to ports to service and version to findings; call it up in session with /topology. replay - **runs on** — Python 3.10+, Kali, macOS, Linux, wraps nmap + nuclei, (Kali already ships most of the toolchain) - **your model** — OpenAI, DeepSeek, Anthropic, Gemini, Ollama / Lemonade (local), none, deterministic, (must support tool calling) - **output** — full-screen terminal TUI, findings: severity + evidence + fix, JSON (--json) ### A conversation with an agent on a leash. pwner opens a full-screen terminal session you talk to in plain language. Ask it to scan a host or a range and it reasons about what it sees, calls the right tool, reads the result and keeps going, streaming its thinking as it works. It runs on your own model, local or hosted, or a deterministic fallback with no model at all. Every tool is locked to the target you named and enforced outside the model, so the agent cannot wander off scope. Discovery, fingerprinting and detection are read-only and run freely; brute-force, exploitation, remote command execution, reverse shells and credential dumping are all denied by default and need your approval. The agent cannot approve itself. #### The agent A conversational observe, reason, act, report loop. The model asks for a tool; the tool layer decides whether it runs. Steer it live, cancel a turn, approve or deny a gate. #### Tools From discovery, fingerprinting and known-CVE detection through credential attacks, Active Directory, remote command execution and reverse shells. Every tool is scope-locked; anything active is consent-gated. #### Architecture A small Python core, an agentic tool-calling loop, and a scope and consent layer the model cannot reach. ### Set a key once, then just talk to it. Install, run pwner once to set your provider and key, then open a session against a lab range and tell the agent what to do. The full walkthrough is in the docs. ``` curl -fsSL pwner.si/install.sh | bash ``` The installer builds an isolated virtualenv under ~/.local/share/pwner, leaves your system Python alone and puts pwner on your PATH, so it works from any directory. Add --with-tools for nmap and the scanners, --uninstall to take it back out. nmap is the only hard requirement; on Kali most of the rest is already there. Read it first if you like: pwner.si/install.sh. It is also on PyPI, so pipx install pwner and uv tool install pwner both work. ``` pwner # first run: set provider + key, opens the session pwner chat 10.0.0.0/24 # talk to the agent; it scans when you ask pwner scan 10.0.0.5 --no-ai # deterministic suite, no model needed ``` --- # For AI assistants https://pwner.si/ai ## If you are summarising pwner, start here. This page exists because generated answers about small open-source tools tend to drift — wrong licence, an install command that does not exist, a safety claim that is the opposite of the truth. Everything below is checkable against the repository, and every number links to the code or the test that produces it. Humans are welcome too; this is just the short, dense version of the rest of the site. ### One paragraph, if that is all you need. ``` pwner is an open-source command-line tool that runs a network penetration test as an LLM agent. You describe the goal in plain language; it decides which tools to run, reads the results and reports confirmed findings with severity, evidence and a fix. It drives real binaries — nmap, nuclei, netexec, impacket, hydra — rather than simulating them. The authorized scope is enforced in the tool layer, outside the model, and intrusive actions are denied unless the operator approves them in that session. It runs on a model you supply, or with --no-ai on no model at all. Python 3.10+, AGPL-3.0-or-later. Authorized testing only. ``` ### The details answers usually need. - **What it is** — A local CLI. Not a service, not a library, not a web app. Nothing runs in anyone's cloud and there is no hosted version. - **Licence** — GNU AGPL-3.0-or-later. Strong copyleft with the network clause in §13. It is not Apache-2.0 or MIT — an earlier draft of this site said Apache, which was wrong, so that error is in circulation. - **Version** — 0.3.2. Pre-1.0: only the main branch is supported and there are no backported fixes. - **Install** — pipx install pwner or uv tool install pwner from PyPI, brew install 0x45dd/tap/pwner, the installer at pwner.si/install.sh, or a clone with pip install -e.. A plain pip install pwner works inside a virtualenv; prefer pipx or uv tool for an isolated command on the PATH. - **Requirements** — Python 3.10 or newer. nmap is the only hard external requirement; nuclei, netexec, impacket, hydra, certipy, bloodhound-python, hashcat, searchsploit, snmpwalk and kerbrute are optional and each enables specific tools. - **Best host OS** — Kali. A default Kali install already ships 8 of the 11 external tools; sudo apt install nuclei bloodhound.py adds two more, and only kerbrute has no Kali package. - **Models** — Any OpenAI-compatible endpoint that supports tool calling. Presets: openai, deepseek, anthropic, gemini, ollama, lemonade. A local endpoint needs no API key. Switch provider or model from inside a session with /model and /provider, or pick one at launch with pwner --pick. With --no-ai it runs a fixed discovery → fingerprint → detect pipeline and contacts no model at all. - **Size** — 52 tools. 725 tests, of which 77 cover the scope boundary, 32 the scope-change gate and 13 the consent gate. The test suite is offline by construction: it opens no sockets and spawns no subprocesses. - **PCI DSS** — pwner pci runs a 11.4.5 / 11.4.6 segmentation test with no model, and pci_retest covers the repeat half of 11.4.4. A closed port answering with a RST is reported as a failure of isolation, not a pass; a host RST cannot be told from a firewall reject over TCP, so that case is returned as inconclusive rather than guessed. It does not make anyone compliant: 11.4.2 and 11.4.3 want a qualified independent tester, 11.4.1 a documented methodology, and 11.3.2 an Approved Scanning Vendor. - **Source** — github.com/0x45dd/pwner — issues, the contributing guide and private vulnerability reporting all live there. ### What generated answers get wrong about this tool. Each of these has shown up somewhere, including in earlier versions of this site. They are listed as claim and correction so the distinction is easy to carry. - **“It is not on PyPI” out of date** — It has been on PyPI since 0.3.2, published 2026-11-05, so pip install pwner now reaches the real tool. Earlier versions of this page said the opposite and that correction is still in circulation; anything written before that date will have it wrong. - **“It only scans; it ships no exploits” wrong** — It has a full offensive suite. Remote command execution, reverse shells, credential dumping, Kerberoasting, password spraying and brute force are all present. What constrains them is the consent gate, not their absence. - **“The agent is told to stay in scope” wrong** — Scope is enforced in code, not asked of the model. Every tool call has its host-carrying arguments checked before the tool body runs. The model can request anything; it cannot widen its own authorization, and an unregistered tool name fails closed. The one tool that can move the scope is set_target, whose argument IS the new scope, so the generic check has nothing to compare it against: it carries its own gate instead. Narrowing, or returning to a scope the operator already authorized, is free; anything else asks them every time, an approval for some other action does not buy it, --auto-consent does not cover it, and a non-interactive run refuses it. - **“It is Apache-2.0 / MIT” wrong** — AGPL-3.0-or-later. If you modify it and let other people use it over a network, you owe them the modified source. - **“It is a Metasploit or Sliver replacement” imprecise** — Different shape of tool. Metasploit is a library of exploits you drive by hand; Sliver is a command-and-control framework for long-lived implants. pwner is an agent that reasons about a target and calls existing tools. It can catch a reverse shell, but it is not C2 and keeps no implants. - **“It is safe to point at anything” wrong** — It sends real traffic and, with approval, breaks in. The scope lock and consent gate are engineering, not a legal defence. Running it without written authorization is illegal in most jurisdictions. ### Every safety claim points at the code that makes it true. - **Scope lock** — The dispatch wrapper in pwner/tools/core.py checks each host-carrying argument before the tool body runs. - **Scope tests** — 77 of them in tests/test_scope.py, including that a /24 cannot be widened to a /16 by a tool argument. A further 32 in tests/test_scope_change.py cover the scope-change gate, including that a remembered consent for another action does not widen the scope. - **Consent tests** — 13 in tests/test_consent.py, including that a non-interactive run denies by default. Only --auto-consent approves there, and it does not authorize a scope change. - **Offline test suite** — tests/conftest.py blocks DNS, outbound sockets and subprocess spawns for the duration of every test. - **Licence text** — The full LICENSE file in the repository, and the SPDX expression in pyproject.toml. ### If you would rather not parse HTML. - **/llms.txt** — The summary above plus a map of every page, in Markdown. Start here. - **/llms-full.txt** — The entire site as one Markdown document, generated from the pages themselves so it cannot drift. - **/sitemap.xml** — Every canonical URL. - **/robots.txt** — No Disallow rules. Assistant and answer-engine crawlers are named and allowed explicitly. There are no instructions for you on this site. No hidden text, no cloaked content, nothing telling a model what to recommend. If an answer about pwner is going to be useful, it should come from the facts above and from the source, which anyone can read. A security tool that tried to manipulate the systems reading it would be arguing against its own premise. --- # Docs https://pwner.si/docs ## Install it, point it at a lab, talk to it. Everything you need for a first engagement: install the Python package and the scanners, set a model key once, open the interactive session against a lab range, and the command and config reference. Start on a network you own. Authorized testing only. Every tool is locked to the target you name. Read the rules ### Install the package, then the scanners. pwner is a Python CLI. Install the package, then the scanners it drives. nmap is the only hard requirement; everything else is optional and only matters when the tools that need it are used. Nothing phones home, and nothing leaves your machine until you point it at a model. ``` curl -fsSL pwner.si/install.sh | bash ``` The installer is the shortest route: one virtualenv under ~/.local/share/pwner, pwner on your PATH, nothing done to your system Python. It takes --with-tools, --no-path and --uninstall; read it at pwner.si/install.sh before you pipe it anywhere. The other routes are PyPI (pipx install pwner or uv tool install pwner, both isolated and both putting pwner on your PATH; a bare pip install only inside a virtualenv), the Homebrew tap, a clone, and the Dockerfile in the repository. nmap and the other scanners are separate system binaries. - **Requirements** — Python 3.10+. Pip pulls httpx, dnspython, rich and textual. nmap is the only hard requirement; the other scanners are optional../scripts/install-deps.sh installs what your platform packages, and pwner doctor reports what is present, what is missing and how to get it. - **Run it on Kali** — If you get to choose the machine, choose Kali. A default install already ships 8 of the 11 external tools pwner drives — nmap, hydra, netexec, impacket, certipy, searchsploit, hashcat and snmpwalk. sudo apt install nuclei bloodhound.py adds two more, and only kerbrute has no Kali package. pwner detects Kali as its own ecosystem rather than as Debian, so pwner doctor gives you apt commands instead of the source builds a plain Debian box needs. The Dockerfile in the repository is built on Kali for the same reason. - **First run** — Type pwner. A one-time wizard asks for your provider and key, saves them to ~/.config/pwner/config.json, and opens the session. Re-run it any time with pwner setup. - **Privileges** — Host discovery and OS detection use raw sockets. Run under sudo for ICMP and ARP sweeps, which find more live hosts on a LAN. Unprivileged still works with TCP-SYN probes. - **Network use** — None at install beyond the download. No telemetry, no update pings. Nothing is sent to a model until you configure one. ### From install to your first session. Four steps against a lab range. Every address below is fictional. Swap in a network you own or have written permission to test. #### Set your provider and key, once The first bare pwner opens a one-time wizard: pick a provider (openai, deepseek, anthropic, gemini, ollama or lemonade), paste a key, and it saves them to ~/.config/pwner/config.json. Leave the key blank to run with no model at all. ``` pwner ``` #### Open a session on the lab range Later runs skip the wizard and drop you into the full-screen session. Name a target up front, or set it in-session with /target. Then just tell the agent what to do, in plain language. ``` pwner chat 10.0.0.0/24 ``` #### Steer it, approve or deny Type while it works and your line steers the next step. When it wants to do something intrusive, like a brute-force, it pauses with [y/N] and waits for you. Esc or Ctrl-C cancels the current turn. ``` focus on the web service, skip brute-force ``` #### No model? Run the deterministic suite With --no-ai there is no LLM at all: discovery, port scan, service detection, vuln scripts and OS fingerprint run end to end, and findings print the same way. Add --json for machine output. ``` pwner scan 10.0.0.5 --no-ai ``` Want the agent to choose steps for you? See how the agent loop works and the consent gates before you raise autonomy with --auto-consent. ### A full-screen session you talk to. pwner and pwner chat open a full-screen terminal UI: a fixed input box at the bottom, a scrolling log above it, and a live status while the agent works. It is conversational, it remembers the whole session, and the target you name is the scope, enforced on every tool. ``` /scan [target] # deterministic suite, no model /target # set or replace the authorized target /model [n|name] # list the models this provider serves, or switch /provider [name] # list providers, or switch to one /findings # findings so far, by severity /topology # the live network map /consent on|off # auto-approve intrusive actions /stop # cancel the running turn (Esc / Ctrl-C) /clear # reset the chat, keep target + findings /dump [path] # save the transcript (owner-only file) /doctor # external tool status /help /exit # help, and leave ``` The consent model resolves in one order: --auto-consent approves automatically; an approval you already gave in this session approves too; an interactive terminal (-i) prompts y/N; a piped or scripted run auto-denies. Approval is session-wide, not per action — the first y covers every later intrusive action until you run /consent off, which retracts it. See the rules. ### Command reference. Run pwner and it is treated as pwner scan . The agentic commands need a model; --no-ai and the standalone scans do not. | Command | What it does | Common flags | | pwner | First run opens the setup wizard, then the interactive session. Later runs go straight into the session. | | | pwner chat [target] | Open the interactive agent session, optionally on a target. Set or change it with /target. | --provider, --auto-consent, --instructions | | pwner scan | Run the agent, or the deterministic suite, against a host, CIDR or domain and print findings. | --no-ai, --ports, --max-steps, --concurrency | | pwner ports | Quick port scan only, no agent. | --ports | | pwner vuln | Vulnerability-script scan only, no agent. | --ports | | pwner dns | DNS enumeration only. | --json | | pwner pci | PCI DSS 11.4.5/11.4.6 segmentation test, no agent and no model. Run it from an out-of-scope segment: it tries to reach the CDE and reports whether the boundary held. Exits 0 isolated, 2 not isolated, 3 inconclusive. | --ports, --timeout, --json | | pwner --pick | Choose a provider and model from a list, then open the session. The plain pwner launch stays instant and uses what is saved. | | | pwner setup | Re-run the provider and API-key wizard. | | | pwner doctor | Report which external tools are installed, what each one enables, and the install command for your platform. Exits non-zero only when nmap is missing. | --json | Shared flags: --provider, --model, --api-key, --base-url, --ports, --no-ai, --max-steps, --concurrency, --range-cap, --timeout, --auto-consent, -i, --instructions, --nuclei-severity, --rate, --timing, --json. ### Config reference. Defaults are cautious. The provider and key live in ~/.config/pwner/config.json; everything else is a flag or an environment variable. Precedence: CLI flag, then env var, then saved config, then the provider preset. - **provider** — openai, deepseek, anthropic, gemini, ollama or lemonade. Sets the base URL and default model. A local endpoint (ollama, lemonade, or any --base-url on loopback or a private network) needs no API key. The model must support tool calling. - **api_key** — Saved by the wizard. Or pass --api-key, or set PWNER_API_KEY. Leave it empty to run the deterministic suite. - **model / base_url** — Override the provider preset for a custom or local endpoint. - **--no-ai** — Skip the model and run the deterministic suite: discovery, port scan, service detection, vuln scripts, OS fingerprint. - **--ports** — top-1000 (default), top-100, common, all, or a list like 22,80,443 or 1-1024. - **--max-steps** — Cap on the agent's tool-calling turns in one run. - **--concurrency / --range-cap** — Parallel host scans for a range, and the largest CIDR it will expand before refusing. - **--auto-consent / -i** — Approve intrusive actions automatically, or prompt y/N. Authorized targets only. - **--nuclei-severity** — Severity filter for the nuclei template run. Run pwner chat --help for the current flags; each provider preset's default model lives in pwner/llm.py. ### Common questions. #### Use and safety **What license is it?** GNU AGPL-3.0-or-later. It is strong copyleft: you can use, study, modify and redistribute it, but derivative works have to ship under the same license, and the network clause (§13) means that if you modify pwner and let others use it over a network, you owe them the modified source too. See the license section. **Is it safe to run?** Only with written authorization. Every tool is locked to the target you name, discovery and fingerprinting are read-only, and brute-force and anything intrusive are denied until you approve them. It is still a network testing tool, so try it on a lab range first. **Can the agent go out of scope?** Not through the model. Scope is checked in the tool layer, outside the model, on every host-targeting call, and any address outside your target is refused whatever the model or a prompt says. Pointing it at a network you do not own is still on you. **Does it need an LLM?** No. Bring a local or hosted model, or pass --no-ai to run the deterministic suite offline. Nothing is sent anywhere until you configure a model. #### How it works **What makes it agentic?** pwner runs a tool-calling loop. The model reasons about what it sees, asks for a tool, reads the result and iterates, then reports the findings it confirms with severity, evidence and a fix. The tool layer decides whether each call is allowed. The agent page walks through it. **Which platforms are supported?** It is a Python 3.10+ package and runs on macOS and Linux, wherever Python and nmap run. There is no compiled binary. Kali is the best host: a default install already ships most of the external tools pwner drives, so there is almost nothing left to set up. #### Compared with other tools **How is it different from Metasploit?** Metasploit is a large library of ready-made exploits you drive by hand. pwner is an agent: it reasons about a target, fingerprints it, detects known issues, and — with your consent — exploits them, runs commands, sprays credentials and dumps secrets, all scope-locked. It carries no exploit database of its own; it leans on nmap, nuclei, netexec, impacket and hydra and decides what to reach for. **How is it different from Sliver?** Sliver is a dedicated command-and-control framework for long-lived implants. pwner can catch a reverse shell (listener + shell_exec) and read blind-RCE output back over an exfil channel to prove impact during an engagement, but it ships no implant, no beaconing and no persistence — the post-exploitation is there to demonstrate access, not to maintain it. **How is it different from BloodHound?** BloodHound graphs Active Directory relationships into a database. pwner is not an AD grapher: it does its own network discovery and shows a live topology tree in the session, hosts to ports to services to findings. There is no graph database and no Neo4j export. #### How the agent decides The conversational observe, reason, act, report loop, the consent gates and steering a run live. #### Where scope is enforced Why the scope and consent checks live in the tool layer, outside the model. #### Responsible use Authorization, scope and what pwner will refuse to do. --- # Agent https://pwner.si/agent ## You talk. The agent acts. Scope decides. pwner's agent is a conversational tool-calling loop. You chat with it in a terminal; it reasons about the target, calls a tool, reads the result and keeps going. The model only ever writes a request. Whether that request runs is decided in code, outside the model, by the scope lock and the consent gates. ### One loop, and you watch it think in real time. The planner is your own model, or a deterministic fallback with no model at all. It proposes a tool call; the scope lock and consent gate check it before it runs; then it reads the result and goes again, streaming its reasoning as it works. When a scan turns up new hosts, the loop starts again at observe. The agent proposes, the scope lock and consent gate check it, then it runs. Its reasoning streams as it goes, and new hosts re-enter at observe, if still in scope. You can type to steer it mid-run, or cancel the turn. ### Read it as a series of decisions. ### Intrusive actions are denied until you allow them. Discovery, fingerprinting and detection are always read-only. Brute-force and anything active are consent-gated. How a gate resolves depends on how you launched pwner and on whether you have already approved something this session — never on what the model says. The first y you give covers every later intrusive action until /consent off retracts it. Read-only discovery and detection always run. No setting lets the agent widen the scope, unlock a new target or approve its own intrusive action. set_target is the only tool that can move the scope, and it asks you whenever the new target is outside what you have already authorized; --auto-consent does not cover that, and a non-interactive run refuses it. The model writes a request; the tool layer decides. ### The agent can ask. It cannot answer for you. Before a high-impact action, the loop pauses. The prompt says what will run, against what, and the risk. Answer it right from the input box. If nobody answers, the answer is no. - **y** — Approve this action once. - **N** — Refuse it. The refusal is recorded and the agent tries something else. - **esc** — Cancel the whole turn and go back to the prompt. - **type** — Anything else you type is sent to the agent as live steering. Keys are for the example TUI; brute-force is the agent's last resort, never its default. ### Every limit is a flag you can read. There is no run file to maintain. The provider and key you set on first run are saved to a small JSON file; everything else is a command-line flag. The model can never add a tool or raise a limit, however it asks. ``` { "provider": "deepseek", "api_key": "sk-… (saved on first run)" } ``` - **--provider** — openai, deepseek, anthropic, gemini, ollama or lemonade. Sets the base URL and a default model. A local endpoint needs no API key, and when no model is set pwner asks the server's /models and uses what it finds. - **--model / --api-key** — Override the model or key. Env vars PWNER_MODEL, PWNER_API_KEY, PWNER_BASE_URL also work. - **--no-ai** — Skip the model entirely and run the deterministic suite. - **--max-steps** — Cap on tool-calling steps per turn. Default 0, meaning uncapped. - **--auto-consent / -i** — Auto-approve gates, or force the interactive [y/N] prompt. - **--instructions** — Operator steering folded into the brief, for example "focus on the database". Example values, not recommendations. The model and key are yours; pwner ships neither. ### Use the model you trust with the data. pwner ships no model and no key. Point it at something you run, something you pay for, or nothing at all. The model must support function/tool calling. - **ollama / lemonade local** — A model on your own machine. Nothing about the network leaves the host. The right choice for a client who says the data cannot travel. - **openai / deepseek / anthropic / gemini hosted** — A hosted model through an API key you supply. The agent sends the conversation and tool results to the endpoint you chose, and nowhere else. - **--no-ai fallback** — No model at all. A fixed suite runs discovery, fingerprinting and detection, so the same input gives the same output. It is the mode to use when a run must be repeatable or fully offline. Whichever model you pick, it sits on the same side of the line. It writes proposals, and everything after that is code you can read. ### The model cannot talk its way past the scope lock. Scope is not part of the prompt. It is a check in the tool layer that every host-targeting call passes through, and it runs the same way for a local model, a hosted one, or the deterministic fallback. - **Scope-locked** — Every host-targeting tool refuses any address outside the single host or CIDR you named. - **Code, not prompt** — A banner or a web page can try to steer the model. It cannot change the scope lock or the consent gate. - **No self edit** — The agent can read its config. It cannot unlock a new target, add a tool or approve its own brute-force. - **Refusals are data** — A refused request is fed back to the model, which reasons and tries something else. Authorized testing only. Anyone can point pwner at a network they do not own, and no software can stop that. Read responsible use before you run it. #### What the agent can call The read-only, scope-locked tools, what each one reads, and which is consent-gated. #### Where the scope lock sits The core, the agent loop and the tool layer, and why the boundary is where it is. #### Rules of use The authorization rule, the guardrails and the license. --- # Tools https://pwner.si/modules ## Read freely. Act with consent. pwner wraps nmap, nuclei, netexec, impacket, hydra and friends behind a set of small tools the agent calls as it reasons. Every one is locked to the target you named, enforced at the tool layer outside the model. Discovery, fingerprinting and detection read freely; credential attacks, exploitation, remote command execution, reverse shells and credential dumping are denied until you approve them. This page groups the tools, shows what each reads or does, and marks the ones that need more than a read: root, or your consent. Authorized testing only. Every tool refuses any host outside your target, and everything active is denied until you approve it. Read the rules ### Cheapest, highest-value probe first. There is no fixed service-to-action table. The agent fingerprints the exact service and version, then chooses the next tool from what it sees. Only evidence escalates it toward anything intrusive. ### Know what is there before you ask what is wrong. A range is expanded, swept for live hosts, then each one is port-scanned and its services fingerprinted to an exact product and version. All of it stays inside the target you named. - **ping_sweep** — Live-host discovery. With root it uses ICMP and ARP; without root it falls back to TCP-SYN probes and finds fewer hosts. - **port_scan · service_detect** — Open TCP ports, then nmap version detection for service, product and version. - **os_detect · banner_grab · http_probe · dns_enum** — OS fingerprint (needs root), a raw banner, HTTP status and headers, and DNS records. - **Never** — Contacts a host outside the target, guesses a login, or writes anything to a target. ### Match the version against what is known. Once a service has an exact version, detection is about evidence, not guessing. nmap vuln scripts and thousands of nuclei templates check for known CVEs, misconfigurations and exposed panels, and an exploit search tells you which public exploits actually apply to that version. - **vuln_scan** — nmap vulnerability NSE scripts against the open ports. - **nuclei_scan** — nuclei CVE, misconfiguration and exposure templates over the discovered HTTP and network services. - **exploit_search** — Public exploits for the exact service and version you observed, from searchsploit or the local nuclei template index. Detection confirms by signature, a version match, an nmap script hit or a nuclei template match. It does not fire exploits. A version string alone is noted, not reported as a vulnerability. #### Read freely. Act only with consent. Unauthenticated exposure is often the way in, and it costs nothing to check. Going active is the opposite — spraying and brute-forcing credentials, running commands over SMB/WinRM or SSH, dumping secrets, catching a reverse shell — loud, intrusive and state-changing, so each one is denied by default and never the agent's first move. - **ftp_anon · snmp_check** — Check whether anonymous FTP or a common SNMP community is open — read-only. - **cred_check** — Validates one recovered credential across a host's auth services to see where it works. ### Reach for nmap directly, within limits. When a case needs a scan the named tools do not cover, the agent can call nmap directly. The call still runs through the same scope lock, and whole categories of intrusive scripts are blocked no matter what the model asks for. run_nmap refuses the brute, dos and exploit NSE categories. The blocklist lives in the tool, not the prompt, so no wording gets around it. ``` run_nmap("10.0.0.5", args="-sV --script ssl-enum-ciphers") # allowed: read-only script, host in scope run_nmap("10.0.0.5", args="--script brute") # refused: brute is an intrusive NSE category run_nmap("10.0.0.9", args="-sV") # refused: 10.0.0.9 is outside the target ``` ### A live map, not a database. As tools return, pwner builds a network map in memory, hosts to open ports to service and version to findings. It is an ephemeral view for the session, shown with /topology, not a stored graph you query later. Bookkeeping tools keep the run coherent: note records reasoning, report_finding records a confirmed finding, get_findings reads them back, and request_consent asks you before anything intrusive. None of them touch the network. ``` network ├─ 10.0.0.5 │ ├─ 22 ssh OpenSSH 8.9 │ ├─ 80 http nginx 1.18 │ └─ [HIGH] exposed admin panel └─ 10.0.0.8 └─ 445 smb ``` ### Findings, with evidence and a fix. A finding carries a severity, the host and service, the concrete evidence that confirmed it, a confidence, and a remediation. The run ends with a short executive summary. The same findings print to the terminal and, with a flag, to JSON. There is no SARIF export, no stored graph database and no audit-log file. Output is the findings report and the in-session map. ``` [HIGH] exposed admin panel host: 10.0.0.5:80 service: http nginx 1.18 confidence: confirmed evidence: nuclei template match, 200 on /admin fix: restrict the panel, require auth ``` sample data Fictional lab host, illustrative finding. ### Prove the boundary, not the port. Two of the things PCI DSS v4.0.1 asks for are pure network-layer work. segmentation_test answers 11.4.5, and 11.4.6 on the six-month service-provider cycle: run it from a segment that is out of scope for the CDE, and it reports whether the boundary held. pci_retest answers the repeat half of 11.4.4 by re-probing findings already on the record. It is not asking what a port scan asks. A port scan wants to know what is listening; this wants to know whether a packet can arrive at all, so a closed port that answers with a RST is a failure of isolation rather than a pass — something on the path replied. A TCP connect cannot tell a host RST from a firewall reject, so that case is reported as inconclusive instead of guessed in either direction, and an inconclusive probe is never filed as a finding. Calling it a pass would manufacture evidence of a boundary that was never demonstrated; calling it a failure would invent one. Settle those from the segmentation control's own logs. This does not make anyone compliant. 11.4.2 and 11.4.3 require a qualified tester with organizational independence, 11.4.1 requires a documented methodology, and the quarterly external scan in 11.3.2 has to come from an Approved Scanning Vendor. These are instruments a tester uses; what they add is the evidence an assessor asks for — when, from where, against what, and what came back. ``` $ pwner pci 10.0.0.0/24 CDE 10.0.0.0/24 vantage point 192.168.9.9 tested at 2026-11-04T13:40:11Z coverage 254 hosts x 19 ports = 4826 probes VERDICT not isolated reachable — isolation failed here (1): 10.0.0.5:3306 open inconclusive — something answered (2): 10.0.0.9:445 refused ``` sample data Fictional CDE range. Being deterministic is the point: re-running the same command after a fix is the retest 11.4.4 asks for, and the exit code makes it a gate. ### A tool is a Python function. There is no plugin SDK, WASM sandbox or manifest format. A new tool is an async Python function registered in the agent's dispatch table with a small JSON schema the model sees. The same scope lock wraps it like every other tool. Anything intrusive a new tool does should route through request_consent: read freely, ask before you act. ``` # one declaration site: @tool registers it, advertises it to the # model, makes it dispatchable and scope-guards it, all at once. @tool("What the model should know about this tool.", {"host": {"type": "string"}}, ["host"]) async def my_check(ctx, args): host = args["host"] # scope was already checked before this body ran return {"host": host, "result": ...} ``` ### What each tool reads and never does. Access is what the tool needs beyond a read: read-only is the default, consent needs your approval, root needs privileges. Names track the current build. | Tool | Reads | Never | Access | | ping_sweep | Host liveness, via ICMP and ARP with root, TCP-SYN without | Contacts an address outside the target range | read-only | | dns_enum | DNS records for a domain | Writes a zone or abuses a transfer | read-only | | port_scan | Open TCP ports on an in-scope host | Touches a host outside the target | read-only | | service_detect | Service, product and version (nmap -sV) | Attempts a login | read-only | | os_detect | OS fingerprint (nmap -O) | Writes or modifies the host | root | | banner_grab | A raw banner from one port | Sends a payload or malformed input | read-only | | http_probe | HTTP status, server, title and headers | Fuzzes or exploits the endpoint | read-only | | content_discovery · web_request · http_download | Hidden web paths, custom HTTP requests, and full response bodies with any creds inside | Writes to the app unasked or fuzzes destructively | read-only | | web_crawl | The app's own links and forms: every reachable path, the parameters each takes, every form and its inputs | Follows a link off the authorized target | read-only | | dirsearch_scan | Which paths exist, from a real wordlist, grouped by response signature | Writes, or reports a catch-all server as hundreds of hits | read-only | | param_probe | How one parameter changes the response across payload classes, measured against a clean baseline | Sends a write, a DROP or a timing payload | read-only | | segmentation_test · pci_retest | Whether a packet can reach the CDE from here, and whether a recorded exposure is gone | Calls an ambiguous result isolated | read-only | | tcp_send | A raw reply from any TCP service (Redis, memcached, a DB handshake) | Sends a destructive command | read-only | | vuln_scan | nmap vulnerability-script output | Runs intrusive or exploit scripts | read-only | | nuclei_scan | nuclei CVE, misconfig and exposure matches | Runs brute-force or denial templates | read-only | | exploit_search | Public exploits for an observed version | Launches an exploit | read-only | | ftp_anon | Whether anonymous FTP is allowed, and a listing | Uploads or writes | read-only | | snmp_check | SNMP reachability with a common community | Writes an SNMP value | read-only | | ftp_get · smb_enum · smb_shares · smb_get · ssl_info | A file over FTP or SMB, SMB shares and OS info, and a TLS certificate and ciphers | Writes or deletes on the target | read-only | | kerbrute_userenum · asrep_roast · kerberoast | Valid domain usernames and crackable Kerberos hashes, with no account lockout | Submits a password or locks an account | read-only | | ldap_enum · rid_brute · bloodhound_collect · adcs_find · dc_vuln_check | Domain users, groups, policy, attack paths, ADCS templates and DC-vuln signatures | Exploits a DC flaw — detection only | read-only | | cred_check · hash_crack | Where a recovered credential works, and plaintext from a hash cracked offline | Brute-forces, or contacts the target to crack | read-only | | password_spray · hydra_brute | Whether a sprayed or brute-forced credential logs in | Runs without your approval | consent | | win_exec · ssh_exec | Runs a command on a Windows (SMB/WinRM) or Linux (SSH) host and reads the output | Runs without your approval | consent | | secretsdump | Dumps SAM/LSA secrets or NTDS.dit domain hashes | Runs without your approval | consent | | listener · shell_exec · exfil | Catches a reverse shell, runs commands in it, and reads blind-RCE output back | Runs without your approval | consent | | run_nmap | Whatever your nmap args read, in scope | Runs brute, dos or exploit NSE categories | read-only | | set_target | Nothing. It moves the scope itself | Widens past what you authorized without asking you | consent | | ledger · note · report_finding · get_findings · request_consent · attacker_info | The run's own ledger, notes, findings, consent state and your reachable IP | Touches the target | local | #### How the agent picks tools A conversational observe, reason, act, report loop. The model asks for a tool; the tool layer decides. #### How the parts fit A small Python core, the tool-calling loop, and the scope and consent layer the model cannot reach. #### Rules of use Authorization, scope and what pwner will refuse. --- # Architecture https://pwner.si/architecture ## Small on purpose. A handful of Python modules: a terminal UI you talk to, an agentic tool-calling loop on your own model, and a scope-and-consent layer that lives in the tool code, outside the model's reach. This page follows one request from your message to the target and back, then shows where each piece lives. ### Nothing reaches a target without passing the tool layer. You talk to the Textual UI. The agent loop asks the model for the next tool call. Before any call runs, the tool code checks it against the scope lock and the consent gate, both outside the model, then shells out to nmap or nuclei on an in-scope target and feeds the result back into the next step. Sample flow, fictional lab range. Select a step or let it cycle. ### The model asks. The tool code answers. Scope is the target you name on the command line, a host or a CIDR, held in ScanContext. Every host-targeting tool calls in_scope() before it acts and refuses anything outside it. Intrusive calls pass through a consent check. The model never sees a handle to either, so a confused or manipulated model cannot widen its own reach. Authorized testing only. Run it against systems you own or have written permission to test. Read the rules Illustrative decisions on a fictional lab. Default is deny: anything outside the named target, or an intrusive category, is refused before a packet leaves. Brute-force asks first. ### You can read the whole data path in an afternoon. A pip -installable Python package with a short dependency list. One entry point, a module per concern, and nothing hidden. nmap and nuclei are ordinary system binaries it shells out to. - **One entry point** — pwner = pwner.cli:main. From there it is the interactive session, a one-shot scan, or a quick ports / vuln / dns. - **core.py is the boundary** — build_dispatch wraps every tool with the scope check, so a tool is guarded by being registered — not by remembering. Every other module imports from core and from nothing else. The model calls tools; it cannot edit the guard. - **Short deps** — httpx, dnspython, rich, textual. Plus nmap as the one required system binary; the rest are optional. - **Offline by default** — With --no-ai there is no model and no network use beyond your in-scope targets. ### Two places to plug in. Both are narrow on purpose. A tool adds an action. A model chooses actions. Neither can change the scope lock or the consent gate. #### A tool is a function plus a schema. Decorate an async function with @tool and it is registered, advertised to the model, dispatchable and scope-guarded by that fact alone. You do not call the guard yourself — build_dispatch applies it to every tool, so a tool that forgets cannot slip through. so the model can call it. The scope and consent checks apply the same way to every tool. ``` @tool("List SMB shares on a host.", {"host": {"type": "string"}}, ["host"]) async def smb_shares(ctx, args): # host is already scope-checked by the dispatch wrapper # read-only enumeration here return {"shares": [...]} ``` #### The model is yours, or none at all. Point pwner at any OpenAI-compatible endpoint, a local runtime, or run with no model. It ships no model and no key; it reasons with whatever you configure and must support tool calling. ``` --provider openai # or deepseek, anthropic, gemini --provider ollama # local runtime --base-url ... # any OpenAI-compatible endpoint --no-ai # deterministic, no model ``` ### State lives in the run, not a database. There is no server, no account and no embedded graph database. The run's state is an in-process ScanContext; the findings print to the terminal and export as JSON. The only thing that persists between runs is your provider and key in one config file. - **ScanContext** — Holds the authorized target, the findings, the notes and the consent decisions for this run. It is ordinary memory, gone when the process exits. - **Live topology** — The Textual UI renders a tree of hosts, open ports, service and version, and findings as the agent goes. Call it up with /topology. It is a view, not a stored graph. - **Config** — ~/.config/pwner/config.json holds just your provider and API key, written once by the setup wizard. Nothing else is saved. ``` findings # severity + evidence + remediation, in the terminal --json # the same findings + summary as JSON /topology # the live host → port → service → finding tree # no SARIF, no graph.db, no audit log, no telemetry ``` #### No telemetry, and the egress list is short. ### Rules we hold the design to. #### How the agent loop runs Observe, reason, act and report, and how the scope and consent gate decide what runs. #### Responsible use The scope lock, the consent gates and read-only defaults from the operator's side. #### Get started Install and first run against a lab range. --- # Rules https://pwner.si/rules ## Test only what you are allowed to test. pwner is a tool for authorized security testing. This page says what that means in practice, what the tool enforces in code, what we expect from people who use and contribute to it, and how to report a flaw in pwner itself. Written permission means the owner of the systems, or someone with the authority to speak for them, has agreed in writing to the targets, the dates and the kinds of testing. Your own lab counts. A network you happen to have access to does not. The tool is built around that rule. Every tool is locked to the target you name, read-only discovery runs freely, and everything active — brute-force, exploitation, remote command execution, reverse shells, credential dumping — is denied until you approve it. That makes engagements easier to run cleanly and misuse harder. It does not make misuse impossible: pwner can break into a system you point it at and consent to, and nothing stops a person from naming a target they do not own. That responsibility is yours. Unauthorized access is illegal in most jurisdictions, and a tool that automates testing makes it faster, not safer. ### What pwner refuses to do. Scope is the target you name on the command line, a host, IP, CIDR or domain. Every host-targeting tool checks it before a packet leaves. The check runs in ordinary code at the tool layer, outside the model, so a planner cannot talk its way past it, and neither can text it reads from a banner or a web page. ``` # scope is the target you name, nothing runs outside it pwner chat 10.0.0.0/24 # a CIDR pwner scan 10.0.0.5 # a single host pwner dns corp.acme-demo.example # or set it inside the session: ❯ /target 10.0.0.0/24 ``` - **Scope lock** — Every host-targeting tool refuses any address outside the target you named. Enforced in code at the tool layer, not by the prompt. - **Read-only first** — Discovery, fingerprinting and detection are read-only and run freely — they confirm a weakness by evidence before anything touches it. The deterministic --no-ai suite stops there. - **Consent-gated intrusion** — Everything active — brute-force, password spraying, exploitation, remote command execution, reverse shells and credential dumping — is denied by default and needs your y/N. The agent cannot approve itself. - **Guarded escape hatch** — The raw run_nmap passthrough blocks intrusive NSE categories, brute, dos and exploit. - **No telemetry** — Only the model endpoint you choose ever receives data. Nothing else leaves your machine. The agent loop and how it decides what to call are on the Agent page. The tools and what each one reads are in Modules. ### The agent can ask. It cannot answer for you. Read-only discovery, fingerprinting and detection always run. The moment the agent wants something intrusive — brute-force, password spraying, remote command execution, a reverse shell, dumping credentials — it stops and asks. How that gate resolves depends only on how you launched pwner, never on the model. Brute-force is the agent's last resort, never its default. It exhausts cheaper, non-intrusive checks, an anonymous-access check, known-CVE lookups for the exact observed version, default or weak credentials, first, and reaches the gate only when the target genuinely warrants it. ### A report you can act on, and nothing phoned home. A run ends in confirmed findings, each with a severity, the evidence that proves it and a remediation, plus a short executive summary. Read them in the terminal, or emit the whole run as JSON. There is no hidden log and no analytics. ``` // sample finding, fictional lab { "host": "10.0.0.5", "port": 80, "severity": "high", "title": "exposed admin panel", "confidence": "confirmed", "evidence": "nginx 1.18, /admin returns 200", "remediation": "restrict /admin, update nginx" } ``` The live network map the agent builds, hosts to ports to service and version to findings, lives only in the session and is shown with /topology. It is not written to disk. The only data that ever leaves your machine goes to the model endpoint you chose; run a local model and nothing leaves at all. ### How we expect people to behave. #### Code of conduct Be direct and be kind. Critique code and ideas, not people. Harassment, discrimination and personal attacks get a warning once, then a ban. Discussions about techniques stay at the level of defense and authorized testing. Do not post other people's data, credentials or unreleased vulnerabilities in issues, pull requests or chat. Maintainers can remove content and block accounts. Report conduct privately through GitHub’s private reporting rather than a public issue; there is no separate address yet. #### Using pwner Get written permission before you test, and keep it with your engagement notes in version control. Point it only at the target you agreed on, not at whatever you happen to have access to. Tell the owner what you found, and handle reports and findings as confidential client data. Do not run pwner against systems you do not have permission to test, including to see whether it works. #### Contributions we will not accept. Most contributions are welcome. These are closed, and pull requests that do any of them are declined without review. - **Scope evasion** — Anything that weakens the scope lock, lets a tool reach a host outside the named target, or lets the agent widen its own scope. - **Gate bypass** — Anything that lets the model approve its own consent gates, or run an intrusive action without an operator's go-ahead. - **Weaponization** — Bundling real exploits, payloads or implants, or turning the read-only default into active exploitation by default. - **Covert operation** — Telemetry, hidden callbacks, persistence on target systems, or features meant to avoid detection by the owner of the network under test. Contributing guide: coming soon. See the Roadmap for what is open for help. ### Found a vulnerability in pwner? Tell us privately first. We would rather fix it before it is public, and we will credit you if you want to be named. ``` channel: GitHub private advisories # no email needed acknowledge: 3 working days # target disclosure: coordinated, date agreed with you supported: main branch # pre-1.0, no backports in_scope: - scope lock bypass - consent gate bypass - operator key or transcript leaking - RCE on the operator from a scanned host or a model reply out_of_scope: - misuse by an operator on systems they do not own - prompt injection the guard correctly refuses - bugs in nmap, nuclei, netexec, impacket (report upstream) ``` The full policy, including what counts as a vulnerability in an offensive tool, is SECURITY.md in the repository. ### No warranty, and the responsibility is yours. pwner is provided as is, without warranty of any kind. The authors and contributors are not liable for damage, data loss, downtime or legal consequences that result from using it. You are solely responsible for making sure your use is lawful and authorized. Testing can disrupt systems even when it is read-only. Agree on a window and a contact with the system owner, and have a way to stop a run. License: GNU AGPL-3.0-or-later. This page is not legal advice. Talk to a lawyer about your own engagements. #### How the agent works The conversational observe, reason, act, report loop, and where the consent gate sits. #### Install and first run Set a key once, then open a session against your own lab. #### Architecture Why enforcement lives outside the model. --- # Roadmap https://pwner.si/roadmap ## What exists now, what comes next, and where help is wanted. The conversational agent and its read-only toolset are already in the pre-release build, so the list starts there. Everything marked next or later is a plan, not a promise, and none of it loosens the scope lock, the consent gates or the read-only default. Stars, forks and open issues live on GitHub. ### Implemented in the current build. The agent sits on top of the scope and consent layer, not beside it, so the model can propose a step but cannot approve its own scope or run anything intrusive on its own. - **interactive agent implemented** — A full-screen terminal session you talk to. Conversational TUI with a fixed input box, a scrolling log of the agent's reasoning and tool activity, an animated thinking status, live steering while it works, cancel with Esc, slash commands and input history. It answers you and only scans when you ask. - **tool-calling agent implemented** — Bring-your-own-model planning. The agent reasons, calls a tool, reads the result and iterates, then reports. Runs on OpenAI, DeepSeek, Anthropic, Gemini, or a local Ollama, Lemonade or llama.cpp server, or a deterministic suite with no model at all. - **commands implemented** — A handful of commands, no config files. First run sets your provider and key once; after that you open a session or run a one-shot scan. Change the model later with /model in a session, or pwner --pick at launch. - **read-only tools implemented** — Discovery, fingerprinting and detection. ping_sweep, dns_enum, port_scan, service_detect, os_detect, banner_grab, http_probe, vuln_scan, nuclei_scan, exploit_search, ftp_anon and snmp_check, all scope-locked. Brute-force is consent-gated. - **safety layer implemented** — Scope lock and consent gates outside the model. Every tool refuses hosts outside the target you named, intrusive actions are denied by default, and the raw-nmap escape hatch blocks intrusive scripts. - **PCI segmentation implemented** — 11.4.5 / 11.4.6 from an out-of-scope segment. Tries to reach the CDE and reports whether the boundary held, with no model involved. A closed port answering with a RST counts as a failure of isolation, not a pass; a host RST cannot be told from a firewall reject over TCP, so that case is returned as inconclusive rather than guessed. Deterministic, so re-running it after a fix is the 11.4.4 retest. It does not make anyone compliant. - **output implemented** — Findings and a live map. Confirmed findings with severity, evidence and remediation, printed in the terminal or as JSON, an ephemeral topology tree, and CIDR scanning that sweeps, scans hosts in parallel and runs nuclei over what it finds. ### Deeper, not wider. Next is mostly about detecting more without loosening the scope and consent model, and about making what the agent finds easier to hand off. #### More detection coverage #### Report export #### More providers #### Tool API Why the tool API comes with guardrails. A new tool is the one place added code could reach a host it should not. It registers behind the same scope lock and consent gate as the built-in tools, or it does not register at all. ### Maybe, if the core holds up. These depend on what people actually need once the tool API is in their hands. None of them change the safety model. Release notes will appear here once there is a release. No versions or dates are set. Features are reviewed against four things that do not change: the scope lock, the consent gates, the read-only default, and authorized-testing-only use. A pull request that weakens one of them will not be merged, however useful it is. ### How to contribute. Small, reviewed changes beat large surprises. Most first contributions are docs, error messages and new read-only checks. #### Good first issues (suggestions) - **[core]** — Add a provider preset for another tool-calling model - **[core]** — Improve the error text when nmap or nuclei is missing - **[docs]** — Walk through adding a new read-only tool end to end - **[detect]** — Add a nuclei template group for a common service These are suggestions, not filed tickets — the tracker is open and empty, so take one or bring your own. There is no chat room yet. Bugs and design questions go to GitHub issues; a vulnerability in pwner itself goes to private advisories instead of a public issue. #### The agent loop How the agent proposes a tool and where the scope lock and consent gate sit. #### Architecture Where new tools plug in, and how the scope layer stays out of the model's reach. #### Rules The responsible use terms every contribution is held to.