Run your first automated pentest
Launch an autonomous web pentest with an active Rules of Engagement, stream it end to end, and email a sealed report.
What you’ll build
A complete automatic pentest against a single web target: you create it, activate a Rules of Engagement that covers the asset, let Rank auto-assign every default agent, stream the agents working in real time, and finish with a sealed report in your inbox. Automatic mode runs every phase end to end and processes the findings inside the same stream, so there is nothing to orchestrate by hand.
Without an active RoE the orchestrator will not start (no_active_roe).
Prerequisites
- A Rank account and an API token (see Authentication).
- The Python SDK or CLI installed.
pip install rank-sdk
export RANK_API_KEY=rk_... npm install -g @aleex-rank/cli
rank auth set rk_... Steps
The same flow works from the CLI, the Python SDK, or the raw REST API. Pick a tab.
-
Create an automatic web pentest. Exactly one asset should be primary;
-usets it.rank pentest create -n "First automated pentest" -u https://example.com -t web -m automaticThe command prints the new pentest
id. Use it below.An active Rules of Engagement is required before the run starts. Set it from the web app, the SDK or the REST API — the CLI does not create RoE. The RoE must cover the target (for example
allowed_domains: ["example.com"]), includeauthorization_refand at least one escalation contact, and be activated. See Engagement & control and the Rules of Engagement recipe. -
Run it. In automatic mode the default agents are auto-assigned and every phase streams to your terminal.
rank pentest run 42 -
List the findings once the run completes.
rank pentest vulns 42
-
Create a chat session and an automatic web pentest.
import rank client = rank.Rank() chat = client.chats.create(nombre="Automated pentest - example.com") pentest = client.pentests.create( name="First automated pentest", url="https://example.com", type="web", mode="automatic", assets=[ {"asset_type": "url", "asset_value": "https://example.com", "is_primary": True}, ], ) -
Activate a Rules of Engagement that covers the target.
activate=Trueis what makes the run legal to start.authorization_refandescalation_contactsare required.client.pentests.roe.create( pentest.id, allowed_domains=["example.com"], authorization_ref="ENG-2026-0042", escalation_contacts=[{"type": "email", "value": "security@example.com"}], activate=True, ) -
Auto-assign the default agents. For an automatic pentest, requesting the defaults assigns every phase.
defaults = client.pentests.agents.default(pentest.id) print(defaults.auto_assigned, defaults.assigned_count) -
Stream the execution. Only
contentevents build the answer;agent_eventitems are live activity.with client.ai.chat.stream( user_prompt="Start the pentest on the configured targets", pentest_id=pentest.id, mode="automatic", chat_id=chat.id, ) as stream: for event in stream: if event.type == "content": print(event.content, end="", flush=True) elif event.is_agent_event: ev = event.agent_event if ev and ev.event_type == rank.AgentEvent.TOOL_CALL: print(f"\n[tool] {ev.data.get('tool_name')}") elif event.type == "complete": print(event.metadata.get("vulnerabilities_stored", 0), "stored") -
Finish the pentest and list the stored vulnerabilities.
client.pentests.finish(pentest.id) vulns = client.pentests.vulnerabilities.list(pentest.id) for v in vulns.items: print(v.id, v.severity, v.vulnerability, v.status) -
Email a sealed report. Pass
formatsandaudiencefor this issuance; Rank emails the PDF only if sealing succeeds. SARIF is a finding export, not a report format.client.pentests.generate_report( pentest.id, recipient_email="you@example.com", extended=1, formats=["pdf", "html"], audience="technical", )
-
Create the pentest on the PHP API. The API key goes in the
X-API-Keyheader.curl https://api.aleex-rank.ai/api/v2/pentests \ -H "X-API-Key: $RANK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "First automated pentest", "type": "web", "mode": "automatic", "assets": [{"asset_type": "url", "asset_value": "https://example.com", "is_primary": true}] }' -
Activate a Rules of Engagement that covers the target.
activate: trueis required for the run to start.curl https://api.aleex-rank.ai/api/v2/pentests/42/roe \ -H "X-API-Key: $RANK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "allowed_domains": ["example.com"], "authorization_ref": "ENG-2026-0042", "escalation_contacts": [{"type": "email", "value": "security@example.com"}], "activate": true }' -
Auto-assign the default agents. For an automatic pentest this single call assigns every phase.
GET /api/v2/pentests/42/default-agents X-API-Key: rk_... -
Start execution on the Go backend, which streams progress over Server-Sent Events.
curl https://aleex.aleex-rank.ai/chat \ -H "X-API-Key: $RANK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_type": "pentest", "pentest_id": 42, "mode": "automatic", "user_prompt": "Start the pentest on the configured targets" }' -
Finish the pentest and read back the findings.
POST /api/v2/pentests/42/finish GET /api/v2/pentests/42/vulnerabilities X-API-Key: rk_... -
Email a sealed report from the Go backend. Optional
formatsandaudienceoverride the profile for this issuance.curl https://aleex.aleex-rank.ai/generate_report \ -H "X-API-Key: $RANK_API_KEY" \ -H "Content-Type: application/json" \ -d '{"pentest_id": 42, "recipient_email": "you@example.com", "extended": 1, "formats": ["pdf", "html"], "audience": "technical"}'
Run it
Save the following as first_automated_pentest.py, set RANK_API_KEY, then run
python first_automated_pentest.py.
"""Run your first automated pentest end to end with the Rank SDK.
What this script does:
1. Creates a chat session so the run has conversation context.
2. Creates an automatic web pentest against a single URL asset.
3. Activates a Rules of Engagement that covers the target.
4. Auto-assigns the default agents for every phase.
5. Streams the execution, printing the assistant's answer and a compact
activity log of agent events as they happen.
6. Marks the pentest as finished and lists the stored vulnerabilities.
7. Emails a sealed report (PDF + HTML, technical audience) to the configured recipient.
In automatic mode the agents run every phase end to end and process the
findings inside the same stream, so by the time the `complete` event arrives
the vulnerabilities are already stored.
Run:
pip install rank-sdk
export RANK_API_KEY=rk_...
python first_automated_pentest.py
Optional environment variables:
RANK_TARGET_URL Target URL to scan (default: https://example.com).
RANK_REPORT_EMAIL Recipient for the sealed report (default: you@example.com).
RANK_AUTH_REF RoE authorization_ref (default: ENG-2026-0042).
"""
from __future__ import annotations
import os
from urllib.parse import urlparse
import rank
TARGET_URL = os.environ.get("RANK_TARGET_URL", "https://example.com")
REPORT_EMAIL = os.environ.get("RANK_REPORT_EMAIL", "you@example.com")
AUTH_REF = os.environ.get("RANK_AUTH_REF", "ENG-2026-0042")
def main() -> None:
# The client reads RANK_API_KEY from the environment automatically.
with rank.Rank() as client:
chat = client.chats.create(nombre=f"Automated pentest - {TARGET_URL}")
pentest = client.pentests.create(
name="First automated pentest",
url=TARGET_URL,
type="web",
mode="automatic",
assets=[
{"asset_type": "url", "asset_value": TARGET_URL, "is_primary": True},
],
)
print(f"Created pentest #{pentest.id} (status: {pentest.status})")
host = urlparse(TARGET_URL).hostname or "example.com"
roe = client.pentests.roe.create(
pentest.id,
allowed_domains=[host],
authorization_ref=AUTH_REF,
escalation_contacts=[{"type": "email", "value": REPORT_EMAIL}],
activate=True,
)
print(f"RoE v{roe.version} status={roe.status}")
# Automatic pentests auto-assign every default agent on first access.
defaults = client.pentests.agents.default(pentest.id)
if defaults.auto_assigned:
print(f"Auto-assigned {defaults.assigned_count} agents across all phases")
# Stream the run. Only `content` events form the assistant's answer;
# `agent_event` items are live activity meant for a timeline view.
print("\n--- Live execution ---\n")
with client.ai.chat.stream(
user_prompt="Start the pentest on the configured targets",
pentest_id=pentest.id,
mode="automatic",
chat_id=chat.id,
) as stream:
for event in stream:
if event.type == "content":
print(event.content, end="", flush=True)
elif event.type == "phase_start":
print(f"\n=== Phase {event.metadata.get('phase_id')} ===")
elif event.is_agent_event:
ev = event.agent_event
if ev is not None and ev.event_type == rank.AgentEvent.TOOL_CALL:
print(f"\n [tool] {ev.data.get('tool_name')}")
elif event.type == "error":
print(f"\nERROR: {event.error}")
elif event.type == "complete":
stored = event.metadata.get("vulnerabilities_stored", 0)
print(f"\n\nExecution complete - {stored} vulnerabilities stored")
# Finalize the pentest and review the findings.
finished = client.pentests.finish(pentest.id)
print(f"\n{finished.message}")
vulns = client.pentests.vulnerabilities.list(pentest.id)
print(f"\nVulnerabilities ({len(vulns.items)} on this page):")
for v in vulns.items:
print(f" [{v.id}] {v.severity:>8} {v.vulnerability} ({v.status})")
# The pentest must be completed before a report can be generated.
report = client.pentests.generate_report(
pentest.id,
recipient_email=REPORT_EMAIL,
extended=1,
formats=["pdf", "html"],
audience="technical",
)
print(f"\n{report.message}")
if __name__ == "__main__":
try:
main()
except rank.AuthenticationError:
print("ERROR: invalid or missing API key. Set RANK_API_KEY.")
except rank.APIError as exc:
print(f"API error ({exc.status_code}): {exc.message}")
Next, try the guided pentest recipe to drive the run phase by phase, the Rules of Engagement recipe for kill and approvals, or the streaming protocol.