Skip to content

Playbooks

A playbook is a Markdown file that tells the analyst how to investigate a specific category of threat. The agent loads the playbook based on ThreatEvent.category, prepends it to the system prompt, and follows it.

Where they live

p3guardian/ai/playbooks/
├── default.md                 ← fallback when no specific playbook matches
├── honeypot.md
├── brute_force.md
├── baseline_new_setuid.md
└── security_updates.md

Adding a new playbook is two steps:

  1. Drop a new .md file in this directory.
  2. Update the routing in analyst.py::_load_playbook() if your category name doesn't auto-map.

That's it. No restart required for new playbooks (loaded on each investigation), but a service reload is needed if you change the routing logic.

Anatomy of a playbook

Every playbook has the same structure:

# <Category> playbook

<one-paragraph description of when this fires>

## Procedura

1. <step 1: what to extract from the event>
2. <step 2: what tools to call, in what order>
3. <step 3: what cross-checks to do>

## Decisione

- **confirmed_threat (confidence X-Y):** <when this verdict applies>
- **false_positive (confidence X-Y):** <when this verdict applies>
- **inconclusive:** <fallback>

## IOC da emettere

- <which IOC types and how to fill them>

## Auto-actions

<what the agent may execute autonomously, or NESSUNA>

The agent doesn't parse the playbook — it just gets it as part of the system prompt. The structure exists for human readability.

Built-in playbooks

honeypot.md

Fires on category=honeypot_hit. Walks the agent through:

  • GeoIP lookup of attacker IP
  • Search honeypot.log for additional hits in the last 24h (recidivist?)
  • Cross-check auth.log for SSH attempts from same IP
  • Decision: confirmed_threat with auto_action=ban_ip if ≥ 2 hits or correlated SSH activity

brute_force.md

Fires on category=ssh_brute_force, failed_password_invalid_user, max_auth_exceeded. The agent:

  • Counts attempts in last 24h, lists targeted usernames
  • Critical check: any Accepted entry for that IP? If yes → CONFIRMED COMPROMISE → CRITICAL
  • Otherwise: bans IP, recommends key rotation if usernames look targeted

baseline_new_setuid.md

Fires on category=baseline_new_setuid. The agent:

  • stat and sha256sum the new binary
  • dpkg -S to check if it belongs to a known package
  • Cross-check dpkg.log ±10 min around the file's mtime for a corresponding install
  • No auto-action — setuid changes need human review (a wrong chmod -s on /usr/bin/sudo locks you out)

security_updates.md

Fires on category=security_updates_pending. The agent:

  • Lists pending packages, weights by criticality (kernel/openssl/openssh = high concern)
  • Extracts CVE IDs from apt changelog for top packages
  • Checks unattended-upgrades status and /var/run/reboot-required
  • No auto-action — patching is operational

default.md

Catch-all. Generic procedure: extract IOC, run geoip, search logs for correlations, pick a verdict. Used when no specific playbook matches the event category.

Writing a new playbook

A good playbook is short (200-500 words), opinionated, and tells the agent what to look for rather than just listing tools. The agent already knows the tools — it needs the priorities.

Bad:

  1. Run run_command to look at logs.
  2. Make a decision.

Good:

  1. Extract the source IP.
  2. Check /var/log/auth.log for prior SSH activity from this IP — especially successful logins.
  3. If ANY successful login exists from this IP in the last 7 days, severity is CRITICAL — possible compromise. Recommend key rotation, do NOT auto-ban yet (the operator may need to investigate the session).
  4. Otherwise, follow standard ban procedure.

Notice the second one tells the agent why (priority signal: prior auth success), and when not to act (don't auto-ban if there might be a real session in progress).

Internationalization

Playbooks are language-agnostic — write them in whatever your team thinks in. Today they're a mix of Italian and English. The LLM handles both fluently. The summary and recommended_actions fields in the final report inherit the language of the playbook.