Ethical contract Ten principles, programmatically enforced. Not advisory.
digger ships with a codified ethical contract — digger.ethics.contract
exposes ten Principle records and a set of assertion helpers
that raise EthicsViolation when violated. These are not
docstrings. State-modifying features call the assertions on the way in;
the test suite has 19 load-bearing tests in
tests/test_ethics.py that fail if a principle's enforcement is
removed.
The contract intentionally mirrors and inverts every offensive capability digger detects against. See Decepticon countermeasures for the contrast table that drove the principle list.
The ten principles
- P1 — Local host only. digger inspects only the host it
runs on.
assert_target_is_localhost(addr, feature)raises on any non-loopback / non-localhost address. - P2 — Observation by default. digger reads; it does not
modify state. Remediation flows are opt-in, route through
confirm_remediation_intent(cmd, interactive=True), and refuse non-interactive sessions. - P3 — No exploitation. digger never sends a payload to
verify a vulnerability.
assert_not_exploitationblocks phrases like "msfconsole", "msfvenom", "sqlmap against", "exploit/...". - P4 — No credential attacks. No brute force, no rainbow
tables, no offline cracking.
assert_not_credential_attackblocks "john the ripper", "hashcat", brute force, rainbow table. - P5 — No third-party surveillance. Out-of-scope user
accounts are off-limits unless explicit consent is recorded.
assert_no_third_party_surveillance(scope). - P6 — No egress without opt-in. Network calls (intel-feed
fetch, LLM triage, TAXII push) require explicit consent; air-gap
mode (
DIGGER_AIRGAP=1) refuses all egress. - P7 — Calibrated findings. Severity reflects evidence strength. The triage runner enforces ICD 203 estimative probability + analytic confidence per finding.
- P8 — No biometric collection. No camera / mic / fingerprint / face capture; no behavioral biometric profiling.
- P9 — Refuse compromised configuration. When pre-flight detects that digger itself has been tampered with (signed-binary mismatch, missing PQC keys, unexpected mode bits), it aborts.
- P10 — Audit-visible. digger never silently filters its own
findings. When a check fires on digger itself, the finding is
emitted with a clear self-attribution note via
digger.opsec.self_id.identify.
Engagement scope (pre-engagement attestation)
Before the first artifact is touched, an EngagementScope is
recorded into the chain of custody. The scope answers four questions in
writing:
| Field group | Captured |
|---|---|
| WHO | investigator name, role, contact, organization |
| WHY | legal authority + written consent reference (ticket / contract clause / email msg-id) |
| WHAT | target hosts + data categories opted in + cross_host_allowed flag |
| WHEN | window start, expected end, retention days, deconfliction notes |
EngagementScope.validate() raises EthicsViolation for
obvious gaps: empty investigator name, multi-host scope without
cross_host_allowed=True, unrecognized data categories,
retention > 10 years.
Remediation gating
Every remediation command emitted by a detector (e.g., the firewall
auditor's "run this to add default-deny inbound") routes through
redact_dangerous_command(cmd) first. The function recognizes
destructive operations — rm -rf, dd of=,
chmod 777, iptables -F with no preservation,
pfctl -d, etc. — and annotates them as destructive in the
output.
digger never applies remediation itself. The
firewall audit CLI prints commands with a [DESTRUCTIVE]
marker on the flagged ones; the operator runs them by hand.
Where the contract is wired in
digger/opsec/airgap.py:assert_network_allowedgates every outbound HTTP call (intel feeds, LLM triage, TAXII).digger/intel/sources/*: every composite feed callsassert_network_allowedat the top offetch_fn.digger/firewall/audit.py: everyRemedy.annotated()routes commands throughredact_dangerous_command.digger/coc/(chain of custody):record_scopeappends the engagement scope tochain_of_custody.jsonand re-validates on load to catch tampering.
Why it's load-bearing
The 19 tests in tests/test_ethics.py include:
test_canonical_principles_present— fails if any principle is deleted from the registry.test_remote_address_refused— fails if P1 stops refusing non-localhost.test_exploitation_intent_refused— fails if P3 stops refusing exploit phrasing.test_credential_cracking_refused— fails if P4 stops refusing brute-force phrasing.test_destructive_commands_redacted— fails if the redactor stops annotating destructive commands.test_remote_target_in_scope_refused_without_flag— fails if a scope can quietly include other hosts.test_scope_roundtrips_through_disk— fails if the chain-of-custody serialization drops scope fields.
A pull request that removes any guardrail breaks the suite, with a test name pointing at the principle.