Run your first automated pentest

Launch an autonomous web pentest, stream it end to end, and email the report.

What you’ll build

A complete automatic pentest against a single web target: you create it, let Rank auto-assign every default agent, stream the agents working in real time, and finish with a PDF 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.

Prerequisites

  • A Rank account and an API token (see Authentication).
  • The Python SDK or CLI installed.

Steps

The same flow works from the CLI, the Python SDK, or the raw REST API. Pick a tab.

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. Auto-assigns the default agents for every phase.
  4. Streams the execution, printing the assistant's answer and a compact
     activity log of agent events as they happen.
  5. Marks the pentest as finished and lists the stored vulnerabilities.
  6. Emails a PDF report 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 PDF report (default: you@example.com).
"""

from __future__ import annotations

import os

import rank

TARGET_URL = os.environ.get("RANK_TARGET_URL", "https://example.com")
REPORT_EMAIL = os.environ.get("RANK_REPORT_EMAIL", "you@example.com")


def main() -> None:
    # The client reads RANK_API_KEY from the environment automatically.
    with rank.Rank() as client:
        chat = client.chats.create(name=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})")

        # 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,
        )
        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, or dig into the streaming protocol.