Operational runbook
The day-to-day operating loop for blue teams and MSSPs: scan → review findings → apply a remediation playbook (dry-run first) → re-scan to verify the finding clears. This page is the practical reference for running that loop, scheduling it, and knowing where the evidence lands.
The operating loop
Every Obexum engagement is a closed verify-loop. You never apply a fix and assume it worked — you re-run the exact check that produced the finding and confirm it no longer fires:
- Scan the target —
obexum scan --target <target> - Review the report and findings —
obexum findings list/ openfindings.html - Triage by severity (CRITICAL → HIGH → IMPORTANT → MEDIUM → LOW)
- Plan a fix — render or dry-run the playbook (
obexum fixis dry-run by default) - Apply in a maintenance window, with the rollback section ready
- Verify by re-scanning and diffing —
obexum scan --target <target>, thenobexum diff
Internally this is the inject → detect → remediate → re-detect cycle the catalogue is validated against: a finding only counts as resolved when the same fingerprint that fired before is gone on re-scan.
1. First scan
If you have not bootstrapped yet, run obexum init once (see the
Quickstart). It creates
~/.obexum/config.yaml, the SSH key folder, the engagement root
~/.obexum/scans/, and the local history database
~/.obexum/obexum.db.
Register a target once, then scan it by short name:
obexum targets add prod-dc-01 \
--type windows-dc \
--host 10.0.0.5 \
--user Administrator
obexum scan --target prod-dc-01
You can also scan ad hoc without registering, by spec —
local://localhost audits the box the scanner runs on, and
ssh://user@host[:port] reaches a remote host over the Obexum SSH
key (Windows over OpenSSH, Linux/BSD over SSH):
obexum scan --target local://localhost
obexum scan --target ssh://root@10.0.0.20:22
Control breadth and outputs per run:
# depth: quick | standard | deep (default from config)
obexum scan --target ssh://Administrator@10.0.0.5 --depth deep
# pick report formats and an output directory for this run
obexum scan --target ssh://Administrator@10.0.0.5 --formats json,html,sarif --output ./reports
# opt into Claude reasoning (costs ~$0.40–$1.60/scan) — off by default
obexum scan --target ssh://Administrator@10.0.0.5 --ai
Every scan ends with a summary block printed to the terminal:
================ SCAN SUMMARY ================
Scan ID: 3f8a1c2e-... # use this id with fix / diff / report
Target: prod-dc-01 (ssh)
Duration: 3m12s
CRITICAL: 2
HIGH: 7
IMPORTANT: 4
MEDIUM: 11
LOW: 6
TOTAL: 30
==============================================
--allow-stale-feed to override on disconnected sites.
2. Read the report
Each scan writes a self-contained engagement directory under
~/.obexum/scans/<scan_id>/. The branded
findings.html is the artefact you open, share, and archive:
# open the HTML report from the most recent engagement
firefox ~/.obexum/scans/$(ls -t ~/.obexum/scans/ | head -1)/findings.html
Or stay on the CLI. These read the engagement findings.json directly:
# rule_ids + severity + count for the latest engagement
obexum findings list
# full evidence + remediation hints for one rule
obexum findings show AUD-WIN-ADCS-001
# point either command at a specific past engagement
obexum findings list --scan 3f8a1c2e-...
Need the report regenerated for a stored scan, or a compliance matrix?
obexum report reads from the local history DB:
# list recent scans (omit --scan-id to discover ids)
obexum report
obexum report --scan-id 3f8a1c2e-... --format markdown
obexum report --scan-id 3f8a1c2e-... --framework cis # or nist | stig | attack | cwe
3. Triage by severity
Obexum scores every finding contextually (CVSS × EPSS × KEV × exposure × data sensitivity) and buckets it into one of five severities. Work them top-down; the patch-posture footer in the summary tells you how many are KEV-active or overdue.
| Severity | Operating guidance |
|---|---|
| CRITICAL | Emergency change. Active exploitation or trivial compromise path. Fix this scan cycle. |
| HIGH | Next maintenance window. Real, demonstrated risk. |
| IMPORTANT | Planned remediation. Meaningful weakening of posture. |
| MEDIUM | Backlog / hardening. Address opportunistically. |
| LOW | Informational / defence-in-depth. Track, don't block on it. |
Findings that share a rule and issue (for example one rule firing across 39 attacker IPs) are aggregated into a single finding with every instance preserved in the description — so the triage list is one row per real issue, not dozens of near-duplicates.
4. Apply a fix safely (dry-run → apply → verify)
Obexum never changes a host on its own. There are two safe paths to a fix, both dry-run-first with a rollback in hand.
Path A — obexum fix (ranked plan, optional execution)
fix turns the findings of a stored scan into a ranked list of
vetted fix groups. It is dry-run by default — with no
--apply it only prints the plan:
# 1. DRY-RUN — show the plan, change nothing
obexum fix --scan-id 3f8a1c2e-...
# 2. APPLY — execute, confirming each group, only low-risk fixes
obexum fix --scan-id 3f8a1c2e-... --apply --risk-max low
# optionally snapshot (LVM/BTRFS) before touching anything
obexum fix --scan-id 3f8a1c2e-... --apply --snapshot
# apply only specific groups (ids from the dry-run table)
obexum fix --scan-id 3f8a1c2e-... --apply --fix-ids a1b2c3,d4e5f6
--risk-max (low|medium|high|manual)
caps which groups auto-apply; --apply alone prompts before each
group. --yes skips every prompt — use it only when you have
already reviewed the dry-run.
Path B — obexum playbook (render a script for change management)
When a change-management reviewer must sign off offline, render the playbook to a script. Obexum does not execute it — the header lists every advisory and the rollback steps sit (commented out) at the bottom of the file:
obexum playbook list --platform windows-dc
obexum playbook show pb-windows-dc-adcs-001
obexum playbook render pb-windows-dc-adcs-001 \
--target prod-dc-01 \
--item OBX_ESC1_AltSAN \
-o fix-ADCS-001.ps1
The rendered script is structured PRE-CHECK → APPLY → POST-CHECK → ROLLBACK, and its header tells you the exact command to verify the fix afterwards.
Verify by re-scan
After the change runs in your window, re-run only the rule that produced the finding. If it no longer fires, the loop is closed:
obexum scan --target ssh://Administrator@10.0.0.5
obexum verify
command with a short-lived, single-finding token. It re-runs that one rule
and posts the verdict (pass = fixed / fail = still present) back to the
portal — the same inject→detect→remediate→re-detect loop,
reported centrally:
obexum verify --upload-token $VERIFY_JWT --portal-url https://obexum.com
5. Schedule recurring scans
Obexum is a single binary with no daemon — schedule it with the tools you already run. The local SQLite DB accumulates history so trends and diffs work across runs.
Linux / macOS — cron (nightly 02:00, append the run log):
# crontab -e
0 2 * * * /usr/local/bin/obexum scan --target ssh://Administrator@10.0.0.5 >> ~/.obexum/cron.log 2>&1
Windows — Task Scheduler (daily DC audit):
schtasks /Create /TN "Obexum DC audit" /SC DAILY /ST 02:00 ^
/TR "C:\obexum\obexum.exe scan --target ssh://Administrator@10.0.0.5"
In CI or with a portal subscription, add --upload-token (or use a
portal-built binary that embeds it) so each scheduled scan auto-uploads its
JSON to obexum.com after writing the local report.
6. Manage engagements & history
Every scan is persisted to ~/.obexum/obexum.db, keyed by scan id.
Track posture over time and compare any two runs:
# recent scans for a target + a trend verdict
obexum history --target prod-dc-01 -n 20
# what changed between a baseline (A) and a newer scan (B)
obexum diff <scan-A-id> <scan-B-id>
# list every NEW / RESOLVED / WORSENED finding, not just the counts
obexum diff <scan-A-id> <scan-B-id> --full
diff is the management view of the verify-loop across a whole
target: it reports NEW, RESOLVED, PERSISTING, WORSENED, and IMPROVED counts
by matching finding fingerprints between the two scans. Run it after a
maintenance window to prove what you closed.
7. Where the evidence lives
Everything for one scan is bundled in its engagement directory — the tree you archive, hand to an auditor, or attach to a ticket:
~/.obexum/scans/<scan_id>/
├── manifest.json # target / OS / counts / timing — machine-readable index
├── findings.json # full findings list (read by `obexum findings`)
├── findings.html # branded HTML report
├── findings.md # markdown report (when in --formats)
├── findings.sarif # SARIF (when in --formats) — for code-scanning UIs
├── scan.log # scan log
└── artifacts/ # per-finding raw probe output, keyed by rule_id
└── <RULE_ID>/
| Path | What it holds |
|---|---|
~/.obexum/scans/ | Engagement root — one sub-directory per scan id. |
~/.obexum/obexum.db | SQLite history used by history, diff, report, and fix. |
~/.obexum/config.yaml | Effective defaults (obexum config prints the resolved view). |
~/.obexum/keys/ | Obexum SSH audit identity — keep at chmod 700. |
~/.obexum/targets.yaml | Named target registry maintained by obexum targets. |
~/.obexum/scans/<scan_id>/
wholesale (it is self-contained), and back up obexum.db so trend
and diff history survive a host rebuild.
Supporting evidence commands
# SPDX 2.3 software bill of materials for the target
obexum sbom -t ssh://root@10.0.0.20 -o sbom-prod.json
# who attacked this host (log forensics + GeoIP + threat-intel attribution)
obexum defend -t prod-web-01