Lab 01 — Engagement Guard and Evidence Verifier
Difficulty: 3/5 | Time: 4–6 hours | Runs locally: yes, standard library only
Pairs with the Phase 00 WARMUP (Chapters 3–7) and HITCHHIKERS-GUIDE. Build a deny-by-default control that decides whether a proposed security test is authorized, and a verifier that proves the evidence you collected has not been altered.
Why This Lab Exists (Purpose & Goal)
Every catastrophic security-engineering mistake in the news began the same way: someone took an action they believed was authorized but could not prove was authorized, against a target that turned out to be out of scope. The line between a professional security engineer and a criminal is not skill — it is provable authorization, containment, and evidence discipline. This is Lab 01 because it is the reflex that makes every sharper tool in the curriculum (fuzzers, container escapes, cloud IAM analysis, AI agents) safe to wield.
The goal is to make authorization a machine-checkable property rather than a feeling. You will build the small program a real engagement runs before every consequential action: it converts a signed rules-of-engagement document into a policy object and answers, deterministically, "is this exact action, against this exact asset, with this technique, at this time, within these limits, allowed right now?" — and refuses, with a named reason, when any predicate fails.
The Concept, In the Weeds
A human agreement ("you may test our staging API next week") is prose; your tools operate on concrete facts — IP addresses, hostnames, technique names, timestamps, request rates, byte counts. The gap between the prose and the facts is where accidents live: an IP reassigned to a different tenant after sign-off, a wildcard domain that silently includes vendor infrastructure, a scan that keeps running after the window closed.
The fix is to evaluate authorization as a conjunction of predicates — every clause must be true, so any single false clause denies the action. That asymmetry (hard to accidentally allow, easy to deny) is the entire point of deny-by-default:
asset ∈ approved_assets
AND technique ∈ approved_techniques
AND start ≤ now ≤ end (timezone-aware UTC)
AND observed_rate ≤ rate_ceiling
AND requested_data ≤ data_ceiling
AND no stop_condition is active ← dominates everything else
Two subtleties this lab forces you to confront:
- Stop conditions are circuit breakers, not prose. A perfectly in-scope, in-window, in-budget action is still denied the instant a stop condition is active. You precommit them so the decision to halt is made calmly in advance, not under the momentum of a live test.
- Integrity ≠ provenance. A SHA-256 digest proves bytes are unchanged since you recorded the
digest — nothing more. It does not prove who collected them, when, or from where. The verifier
uses a constant-time comparison (
hmac.compare_digest) so an attacker cannot learn the expected digest byte-by-byte through timing.
Why This Matters for Protecting the Company
When you join a security team, you are not trusted with production access, red-team scope, or a vulnerability-reward-program queue until you demonstrate exactly this behavior. A tester who cannot prove authorization exposes the company to legal liability (the CFAA and its global equivalents criminalize unauthorized access regardless of intent); a tester who contaminates evidence destroys the company's ability to act on a finding or defend itself; a tester who ignores a stop condition can turn an assessment into an outage or a breach. This control is the difference between a security program that reduces risk and one that creates it.
What You're Building
ProposedAction (operator, asset, technique, time, rate, data)
│
▼
authorize_action(policy, action) ──▶ Decision(allowed, reason, failed_control)
│ └─ logged with NO secrets, names the failed control
NetworkPolicy.allows(src, dst, port) ──▶ only declared zone pairs reachable
sha256_file / verify_evidence ──▶ tamper-evident, constant-time
How This Is Used on the Job
This is not a toy — it is the shape of real tooling. A pentest orchestrator gates every scanner launch through an authorization function like this. A bug-bounty automation pipeline refuses to send traffic to a host absent from the program scope. An incident-response evidence vault verifies every artifact's hash on ingest and rejects a mismatch loudly. The exact same deny-by-default policy shape reappears later as cloud IAM (Phase 07), Kubernetes admission control (Phase 07), Android component-export checks (Phase 04), sandbox policy (Phase 06), and AI-agent tool gating (Phase 11). You are building the spine of the whole discipline here.
Attack / Failure Cases You Must Handle
- An operator supplies an adjacent but unapproved hostname (asset-scope drift).
- A permitted target is tested with a prohibited technique (technique drift).
- A request starts outside the approved UTC window (time drift).
- The requested rate or data volume exceeds the engagement ceiling (data/rate drift).
- A safety stop is active but the target/technique are otherwise valid (stop dominates).
- An evidence file changes after collection (tamper detection).
- A lab network flow crosses an undeclared zone boundary (containment).
Build Order
EngagementPolicy.validate— reject a malformed policy (fail closed).authorize_action— the conjunction above, returning a named failed control.sha256_fileandverify_evidence— hashing + constant-time verification.NetworkPolicy.allows— only declared(source, destination, port)flows.Decision.to_json— a decision record with no secrets and the failed control.
Run
python -m pip install -r requirements.txt
pytest test_lab.py -v
LAB_MODULE=solution pytest test_lab.py -v
Security Properties (Invariants)
- a malformed policy fails closed;
- exact asset matching — no suffix/wildcard guessing;
- any active stop condition denies all actions;
- timestamps are timezone-aware;
- evidence comparison is constant-time;
- network paths absent from policy are denied;
- decision logs omit secrets and include the failed control.
Validation — What You Should Be Able to Do Now
After this lab you can, without notes:
- Refuse an out-of-scope action and name the exact failed predicate, rather than waving at "it felt wrong." This is the answer interviewers want when they ask "the client verbally asks you to test a new asset — what do you do?"
- Explain why a VM, a VPN, a disclaimer, or a public bug-bounty page is not sufficient authorization — because none of them is a record a court, an auditor, or a teammate can check.
- Distinguish integrity from provenance and explain why a matching hash is necessary but not sufficient evidence.
- State the stop-condition override semantics and why "stopping correctly" is a success, not a failure.
The Broader Perspective
You just built, in miniature, a policy decision point (PDP) — the architectural pattern that governs access in every serious system you will ever secure. The mental move you practiced — convert a human agreement into versioned, evaluated-before-every-action policy data, and fail closed on ambiguity — is the single most transferable idea in security engineering. When you later look at an over-permissive IAM role, a lenient admission controller, or an agent that runs whatever the model proposes, you will recognize them all as the same failure: authority that wasn't evaluated deny-by-default against an explicit policy. Carry this forward; it is the lens for the entire track.
Interview Angle
- "What would make you stop an assessment immediately?" — Any active stop condition (unexpected third-party data, instability, scope ambiguity, runaway cost, evidence-integrity failure, signs of a real intrusion, owner stop). Stop conditions override all permissions.
- "Why hash evidence, and why isn't a hash enough?" — A hash makes the artifact tamper-evident from a point in time; trustworthiness also needs provenance (collector, tool, UTC time, clock source) and access controls.
Extension (Stretch)
Sign the policy file; add CIDR support with ipaddress; connect the decision function to a local
scanner wrapper that refuses to launch unless authorization succeeds.
References
- NIST SP 800-115 (testing methodology, rules of engagement); NIST SP 800-86 (evidence concepts).
- disclose.io safe-harbor templates; CFAA / Computer Misuse Act overview (Phase 00 WARMUP, Ch. 2).
- Phase 00 WARMUP Chapters 3–7.