Security Model¶
Design Philosophy¶
AIIR runs on isolated forensic workstations behind firewalls. The primary security boundary is network isolation and VM/container isolation, not in-band command filtering. The controls described here are defense-in-depth measures within that boundary.
Network Assumptions¶
All AIIR components are assumed to run on a private forensic network:
- Not exposed to incoming connections from the Internet
- Not exposed to untrusted systems
- Protected by firewalls on a trusted network segment
- Outgoing Internet connections are required for report generation (Zeltser IR Writing MCP) and optionally for threat intelligence (OpenCTI) and documentation (MS Learn MCP)
wintools-mcp must only be installed on dedicated forensic workstations. Never install on personal laptops, production systems, or machines containing data outside the scope of the investigation.
Authentication¶
Gateway (sift-gateway)¶
Bearer token authentication on all MCP and REST endpoints (health check excepted). Tokens use the aiir_gw_ prefix with 24 hex characters (96 bits of entropy).
API keys map to examiner identities in gateway.yaml. The examiner name is injected into backend tool calls for audit attribution.
When installed with --remote, TLS is enabled with a local CA certificate.
wintools-mcp¶
Bearer token authentication with aiir_wt_ prefix. Generated during installation. Every request requires Authorization: Bearer <token>. The --no-auth flag is for development only.
Execution Security¶
sift-mcp (Linux)¶
- Denylist: Blocks destructive system commands (mkfs, dd, fdisk, shutdown, etc.). When Claude Code is the client, additional case-file-specific deny rules are deployed (see L3 below).
- subprocess.run(shell=False): No shell, no arbitrary command chains
- Argument sanitization: Shell metacharacters blocked
- Path validation: Kernel interfaces (/proc, /sys, /dev) blocked for input
- rm protection: Case directories protected from deletion
- Output truncation: Large output capped
- Flag restrictions: Certain tools have specific flag blocks (find blocks
-exec/-delete, sed blocks-i, tar blocks extraction/creation, etc.)
Uncataloged tools can execute with basic response envelopes. Catalog enrollment is for FK enrichment, not access control.
wintools-mcp (Windows)¶
- Catalog allowlist: Only tools defined in YAML catalog files can execute
- Hardcoded denylist: 20+ dangerous binaries blocked (cmd, powershell, pwsh, wscript, cscript, mshta, rundll32, regsvr32, certutil, bitsadmin, msiexec, bash, wsl, sh, msbuild, installutil, regasm, regsvcs, cmstp, control — including .exe variants)
- subprocess.run(shell=False): No shell, no command chains
- Argument sanitization: Shell metacharacters, response-file syntax (
@filename), dangerous flags, and output redirect flags all blocked - Output directory control: Zimmerman tool wrappers hardcode the output directory; user-supplied flags cannot override it
The installer requires typing security_hole (or passing -AcknowledgeSecurityHole) as an intentional friction point.
Human-in-the-Loop Controls¶
Nine layers of defense-in-depth protect the integrity of forensic findings. The HMAC verification ledger (L2) is the cryptographic guarantee. The other layers are advisory controls that raise the bar.
L1 — Structural Approval Gate¶
All findings and timeline events stage as DRAFT. Only a human examiner can move them to APPROVED or REJECTED — via the aiir CLI (password entry at /dev/tty) or the case dashboard (challenge-response authentication in the browser). There is no MCP tool for approval. The AI cannot bypass either mechanism: the CLI reads the password from /dev/tty (not stdin), and the dashboard requires computing HMAC(PBKDF2(password), nonce) which the AI cannot do without the password.
L2 — HMAC Verification Ledger¶
When an examiner approves findings, an HMAC-SHA256 signature is computed over the substantive text (observation + interpretation for findings, description for timeline events) using a key derived from the examiner's password (PBKDF2, 600K iterations). These signatures are stored in /var/lib/aiir/verification/{case-id}.jsonl — outside the case directory and outside the Claude Code sandbox.
aiir review --verifyperforms full HMAC verification with per-examiner password promptsaiir review --verify --minefilters to the current examiner only- Report generation includes automatic reconciliation (no password needed) that detects mismatches between approved items and ledger entries
- Password rotation (
aiir config --reset-password) re-signs all ledger entries with the new key - Case close copies the verification ledger into the case directory for archival
The LLM cannot forge ledger entries because it does not know the password-derived key.
L3 — Case Data Deny Rules¶
When Claude Code is the LLM client, 41 deny rules block Read/Edit/Write tool access to protected files:
- Case data:
findings.json,timeline.json,approvals.jsonl,todos.json,CASE.yaml,actions.jsonl,audit/*.jsonl,evidence.json,pending-reviews.json - System:
/var/lib/aiir/**(verification ledger + password hashes) - CLI:
Bash(aiir approve*)andBash(aiir reject*)(including path-qualified variants) - Control files:
.claude/settings.json,.claude/CLAUDE.md,.claude/rules/**,.aiir/hooks/**,.aiir/active_case,.aiir/gateway.yaml,.aiir/config.yaml,.aiir/.password_lockout
These rules replace the previous generic denylist (rm -rf, mkfs, dd) with targeted protection for case integrity.
L4 — Sandbox Filesystem Write Protection¶
sandbox.filesystem.denyWrite uses bwrap to OS-enforce write blocking on protected paths. Bash commands run inside the sandbox cannot modify these files regardless of the shell construct used (sed -i, perl -i, redirections, etc.). Protected paths include ~/.aiir/gateway.yaml, ~/.aiir/config.yaml, ~/.aiir/active_case, ~/.aiir/hooks, ~/.claude/settings.json, ~/.claude/CLAUDE.md, and ~/.claude/rules. MCP backends run outside the sandbox and can write case data normally.
L5 — File Permission Protection¶
Case data files with forensic value (findings.json, timeline.json, approvals.jsonl) are set to chmod 444 (read-only) after every write. The owning process unlocks before writing and relocks after. This is a speed bump, not a wall — the LLM process can chmod — but combined with deny rules and the PreToolUse hook it adds another layer.
At case initialization, the filesystem is checked. Non-POSIX filesystems (NTFS, exFAT, VFAT) trigger a warning since chmod has no effect.
L6 — Report Reconciliation¶
When generating reports, report-mcp performs a bidirectional reconciliation between approved items and the verification ledger. This does not require a password. It detects:
- Items approved but missing from the ledger (APPROVED_NO_VERIFICATION)
- Ledger entries with no corresponding approved item (VERIFICATION_NO_FINDING)
- Substantive text changed after signing (DESCRIPTION_MISMATCH)
- Count mismatches between approved items and ledger entries
Alerts are included in the generated report as verification_alerts.
L7-L8 — Integrity Controls¶
- Password authentication: Both the
aiir approveCLI command and the dashboard Commit button require password-based authentication. The CLI uses direct password entry via/dev/tty. The dashboard uses challenge-response: the browser derives a PBKDF2 key and computes HMAC-SHA256(key, server_nonce) — the password never leaves the browser. Passwords are set per examiner viaaiir config --setup-password(minimum 8 characters). - Provenance enforcement: Findings must be traceable to evidence (MCP > HOOK > SHELL > NONE). NONE provenance with no supporting commands is rejected by a hard gate in
record_finding(). - Content hash integrity: SHA-256 hashes computed at staging, verified at approval.
aiir review --verifydetects post-approval tampering via cross-file hash comparison.
L9 — Kernel Sandbox (bubblewrap)¶
Claude Code's sandbox uses bubblewrap (bwrap) to isolate Bash commands in
Linux namespaces. It enforces network isolation (--unshare-net) and PID
namespace isolation (--unshare-pid), plus filesystem write restrictions
(only the working directory is writable). MCP servers run outside the sandbox
with full access. Only Bash commands and their children are confined.
On non-setuid bwrap (all Ubuntu 18.10+), namespace creation requires unprivileged user namespace support in the kernel. Multiple mechanisms can block this:
| Mechanism | Versions | Detection |
|---|---|---|
AppArmor restrict_unprivileged_userns |
Ubuntu 23.10+ | sysctl check + AppArmor profile fix |
unprivileged_userns_clone=0 |
Any (hardened kernels, cloud images) | sysctl check + persistent fix |
| Container restrictions | Any | systemd-detect-virt + marker files + cgroup check |
| WSL1 | Any | uname -r check |
max_user_namespaces=0 |
Any | sysctl check |
setup-sift.sh detects these restrictions at install time and provides
environment-specific remediation. On Ubuntu 23.10+, it writes a targeted
AppArmor profile at /etc/apparmor.d/bwrap that grants only /usr/bin/bwrap
the userns permission. On older systems with unprivileged_userns_clone=0,
it provides the sysctl command to re-enable user namespaces.
aiir setup test includes a sandbox health check with the same diagnostic
cascade.
If the sandbox cannot be enabled (e.g., containers without privileged
namespaces), Claude Code's enableWeakerNestedSandbox setting provides
partial isolation (network + filesystem restrictions remain, process
isolation is reduced). By default, allowUnsandboxedCommands: false means
Claude Code will refuse to run Bash commands rather than running them
unsandboxed.
Provenance Tiers¶
| Tier | Source | Trust Level |
|---|---|---|
| MCP | MCP audit log | System-witnessed |
| HOOK | Claude Code hook log | Framework-witnessed |
| SHELL | supporting_commands parameter |
Self-reported |
| NONE | No audit record | Rejected |
Claude Code Controls¶
When Claude Code is the LLM client, aiir setup client --client=claude-code deploys:
- Kernel-level sandbox: Restricts Bash writes and network access via bubblewrap (L9). On Ubuntu 24.04+, requires AppArmor profile installed by
setup-sift.sh - Case data deny rules: 41 rules blocking Read/Edit/Write to protected case files, evidence registry, verification ledger, and control files (L3)
- PreToolUse hook: Blocks Bash redirections targeting protected files (L4)
- PostToolUse audit hook: Captures every Bash command and output to
audit/claude-code.jsonl - Provenance enforcement: Findings without an evidence trail are rejected
- Password-gated human approval: Approval requires the examiner's password + writes HMAC ledger entry (L2)
SSH Security Consideration¶
Remote deployments (Path 2) require SSH access to SIFT only for CLI-exclusive operations: case initialization, evidence registration, evidence unlocking, and command execution. Finding approval and rejection are available through the case dashboard in the browser — SSH is not required for the review workflow.
If the remote LLM client has terminal access (e.g., Claude Code), it can potentially use the examiner's SSH credentials to run commands on SIFT outside of MCP controls. The password gate prevents the LLM from approving findings — whether through the CLI (/dev/tty password entry) or the dashboard (challenge-response authentication). Other operations (file modification, evidence access) are not password-gated.
For production forensic work with remote Claude Code, examiners should use SSH authentication that requires human interaction per use:
- Password-only authentication (no agent-forwarded keys)
ssh-add -cfor per-use agent confirmation- Hardware security keys (FIDO2/U2F)
Alternatively, MCP-only clients (Claude Desktop, LibreChat) eliminate this concern entirely — they can only reach SIFT through audited MCP tools.
Adversarial Evidence¶
Evidence under analysis may contain attacker-controlled content designed to manipulate LLM analysis. Any text field in any artifact — filenames, event log messages, registry values, email subjects, script comments, file metadata — could contain adversarial instructions.
Defenses:
- AGENTS.md rules: Instruct the LLM to never interpret embedded text as instructions
- data_provenance markers: Every tool response tags output as untrusted
- Discipline reminders: Rotating forensic methodology reminders in every response
- HITL approval gate: The primary mitigation — humans review all findings
Evidence Handling¶
Never place original evidence on any AIIR system. Only use working copies for which verified originals or backups exist.
Any data loaded into the system runs the risk of being exposed to the underlying AI provider. Only place data on these systems that you are willing to send to your AI provider. Treat all AIIR systems as analysis environments, not evidence storage.
Evidence Integrity Measures¶
- SHA-256 hashes computed at registration, verified on demand via
aiir evidence verify - Evidence registry (
evidence.json) protected by deny rules to prevent hash tampering - Evidence access is logged to
evidence_access.jsonl aiir evidence locksets the entire evidence directory to read-only (chmod 444/555)aiir evidence unlockrestores write access for re-extraction
These are defense-in-depth measures. Hash-based verification is the primary integrity mechanism. Proper evidence integrity depends on verified hashes, write blockers, and chain-of-custody procedures that exist outside this platform.
Filesystem Requirements¶
- ext4: Recommended. Full permission support for read-only protection.
- NTFS/exFAT: Acceptable. File permission controls will be silently ineffective.
- FAT32: Discouraged. 4 GB file size limit.
Audit Trail¶
Every MCP tool call is logged to a per-backend JSONL file in the case audit/ directory:
audit/
├── forensic-mcp.jsonl
├── case-mcp.jsonl
├── report-mcp.jsonl
├── sift-mcp.jsonl
├── forensic-rag-mcp.jsonl
├── windows-triage-mcp.jsonl
├── opencti-mcp.jsonl
├── wintools-mcp.jsonl
└── claude-code.jsonl # PostToolUse hook (Claude Code only)
Each entry includes:
- Unique evidence ID ({backend}-{examiner}-{date}-{seq})
- Tool name and arguments
- Timestamp
- Examiner identity
- Case identifier
Evidence IDs resume sequence numbering across process restarts.
Responsible Use¶
This project demonstrates the capabilities of AI-assisted incident response. While steps have been taken to enforce human-in-the-loop controls, it is ultimately the responsibility of each examiner to ensure that their findings are accurate and complete. Ultimate responsibility rests with the human. The AI, like a hex editor, is a tool to be used by properly trained incident response professionals. Users are responsible for ensuring their use complies with applicable laws, regulations, and organizational policies.