g;
description: string;
schema: z.ZodTypeAny;
execute: (params: z.infer<typeof this.schema>) => Promise<ToolOutput>;
}
export interface ToolOutput {
evidenceId: string;
rawOutput: string;
metadata: Record<string, unknown>;
timestamp: string;
}
export class SealedToolRegistry {
private tools: Map<string, InvestigationTool> = new Map();
register(tool: InvestigationTool): void {
this.tools.set(tool.name, tool);
}
getTool(name: string): InvestigationTool | undefined {
return this.tools.get(name);
}
listTools(): string[] {
return Array.from(this.tools.keys());
}
}
**Why this choice:** A registry pattern enforces deterministic execution. The AI cannot invent commands; it can only request registered tools. This eliminates shell injection risks and ensures every operation maps to a known forensic surface.
### Step 2: Implement the Policy Enforcement Engine
The policy engine intercepts all AI requests and validates them against a read-only constraint set. It blocks any operation that modifies host state, alters configurations, or terminates processes. Requests that pass validation are forwarded to the tool registry; denied requests are logged and returned with a rejection reason.
```typescript
export class ReadOnlyPolicyEngine {
private blockedActions: Set<string> = new Set([
'kill_process',
'delete_file',
'modify_registry',
'restart_service',
'block_ip',
'disable_account'
]);
validate(request: { toolName: string; params: Record<string, unknown> }): PolicyResult {
const tool = registry.getTool(request.toolName);
if (!tool) {
return { allowed: false, reason: 'Tool not registered' };
}
const hasMutation = this.blockedActions.has(request.toolName);
if (hasMutation) {
return { allowed: false, reason: 'Mutation detected in read-only policy' };
}
return { allowed: true, reason: 'Policy passed' };
}
}
export interface PolicyResult {
allowed: boolean;
reason: string;
}
Why this choice: Policy enforcement operates at the framework level, not the model level. This ensures defense-in-depth: even if the AI generates a malicious or erroneous request, the engine blocks it before execution. The blocked action set explicitly defines the investigation boundary.
Step 3: Route Through the Audit Logger
Every tool execution, whether allowed or denied, must be recorded. The audit logger captures the request payload, policy decision, raw output, and evidence identifier. This creates an immutable chain of custody that responders can review, challenge, or reproduce.
export class AuditLogger {
private entries: AuditEntry[] = [];
log(entry: AuditEntry): void {
this.entries.push({
...entry,
recordedAt: new Date().toISOString()
});
}
getChain(): ReadonlyArray<AuditEntry> {
return Object.freeze([...this.entries]);
}
}
export interface AuditEntry {
requestId: string;
toolName: string;
params: Record<string, unknown>;
policyDecision: 'allowed' | 'denied';
evidenceId?: string;
rawOutput?: string;
recordedAt: string;
}
Why this choice: Forensic reproducibility requires complete visibility into the investigation path. By logging at the framework level, you prevent gaps in the evidence chain and enable post-incident review without relying on AI summaries.
Step 4: Enforce Explicit Heavy Diagnostic Gates
Certain operations, such as heap dumps, flight recorder captures, or full memory snapshots, carry significant performance and stability risks. These must never be triggered implicitly. A heavy diagnostic gate requires explicit operator flags or multi-step approval before execution.
export class HeavyDiagnosticGate {
private heavyTools: Set<string> = new Set([
'heap_capture',
'jfr_snapshot',
'full_memory_dump',
'kernel_trace'
]);
async requestApproval(toolName: string, context: string): Promise<boolean> {
if (!this.heavyTools.has(toolName)) return true;
console.warn(`[GATE] Heavy diagnostic requested: ${toolName}`);
console.warn(`[GATE] Context: ${context}`);
console.warn(`[GATE] Awaiting explicit operator approval...`);
// In production, this would integrate with a confirmation UI or API
const approved = await this.waitForOperatorConfirmation();
return approved;
}
private async waitForOperatorConfirmation(): Promise<boolean> {
return new Promise((resolve) => {
// Simulated approval flow
setTimeout(() => resolve(true), 2000);
});
}
}
Why this choice: Heavy diagnostics can degrade host performance, trigger EDR alerts, or consume disk space rapidly. Explicit gating ensures operators understand the impact before execution. This is critical during Java memory-shell investigations, where heap analysis reveals injected agents but requires careful resource management.
Step 5: Assemble the Investigation Orchestrator
The orchestrator ties the components together. It receives AI-generated plans, validates each step through the policy engine, executes approved tools, logs results, and enforces heavy diagnostic gates. It also generates a coverage report that explicitly states which surfaces were examined and which remain unverified.
export class InvestigationOrchestrator {
constructor(
private registry: SealedToolRegistry,
private policy: ReadOnlyPolicyEngine,
private logger: AuditLogger,
private gate: HeavyDiagnosticGate
) {}
async executePlan(plan: InvestigationStep[]): Promise<InvestigationReport> {
const results: ToolOutput[] = [];
const gaps: string[] = [];
for (const step of plan) {
const policyCheck = this.policy.validate(step);
if (!policyCheck.allowed) {
this.logger.log({
requestId: step.requestId,
toolName: step.toolName,
params: step.params,
policyDecision: 'denied',
recordedAt: new Date().toISOString()
});
gaps.push(`Blocked: ${step.toolName} - ${policyCheck.reason}`);
continue;
}
const approved = await this.gate.requestApproval(step.toolName, JSON.stringify(step.params));
if (!approved) {
gaps.push(`Skipped: ${step.toolName} - Operator denied heavy diagnostic`);
continue;
}
const tool = this.registry.getTool(step.toolName);
if (!tool) {
gaps.push(`Missing: ${step.toolName} - Not registered`);
continue;
}
const output = await tool.execute(step.params);
this.logger.log({
requestId: step.requestId,
toolName: step.toolName,
params: step.params,
policyDecision: 'allowed',
evidenceId: output.evidenceId,
rawOutput: output.rawOutput,
recordedAt: new Date().toISOString()
});
results.push(output);
}
return {
evidence: results,
coverageGaps: gaps,
generatedAt: new Date().toISOString()
};
}
}
export interface InvestigationStep {
requestId: string;
toolName: string;
params: Record<string, unknown>;
}
export interface InvestigationReport {
evidence: ToolOutput[];
coverageGaps: string[];
generatedAt: string;
}
Why this choice: The orchestrator enforces the complete safety boundary in a single execution path. It ensures policy validation, heavy diagnostic gating, audit logging, and gap analysis occur consistently. The coverage report prevents false confidence by explicitly listing unverified surfaces.
Pitfall Guide
1. Unbounded Shell Access
Explanation: Granting the AI direct access to exec(), bash, or raw command strings allows it to bypass safety boundaries. Models will often chain commands, redirect output, or attempt remediation when faced with ambiguous signals.
Fix: Route all execution through a sealed tool registry. Never expose raw shell interfaces to the AI planner. Validate every request against a read-only policy before execution.
2. Conflating Triage with Containment
Explanation: Incident response workflows often blur the line between investigation and mitigation. AI models optimized for task completion will attempt to kill processes, block IPs, or disable accounts when they detect suspicious activity, potentially destroying evidence or causing service outages.
Fix: Architecturally separate investigation endpoints from response endpoints. The AI framework should only expose read-only tools. Containment actions must be triggered by human operators or dedicated SOAR playbooks after triage completes.
3. Implicit Heavy Diagnostics
Explanation: Heap dumps, JFR captures, and full memory snapshots are resource-intensive. If the AI triggers these automatically during early triage, it can degrade host performance, fill disk space, or trigger EDR heuristics.
Fix: Implement explicit diagnostic gates. Require operator confirmation or multi-step approval for any tool marked as high-impact. Log all heavy diagnostic requests separately for forensic review.
4. Opaque Evidence Chains
Explanation: AI models often summarize findings in natural language, discarding raw outputs. This breaks the chain of custody and makes it impossible to verify or challenge conclusions.
Fix: Store raw command outputs as immutable artifacts linked to unique evidence IDs. Never replace raw data with AI summaries. The audit logger must preserve the exact output returned by each tool.
5. Missing Gap Analysis
Explanation: AI reports frequently state "no threats detected" without clarifying which surfaces were examined. This creates false confidence and leaves investigation blind spots.
Fix: Mandate a coverage report that explicitly lists unverified surfaces, blocked requests, and skipped diagnostics. The orchestrator should generate this report automatically after plan execution.
6. Bypassing Audit Logs
Explanation: Direct tool execution or framework modifications can create gaps in the audit trail. If logs are incomplete, post-incident review becomes unreliable.
Fix: Intercept all tool calls at the framework level before OS execution. Ensure the audit logger is write-once and append-only. Integrate with centralized logging systems to prevent local tampering.
7. Over-Reliance on AI Reasoning
Explanation: Treating AI output as authoritative rather than advisory leads to confirmation bias. Models can hallucinate evidence, misinterpret logs, or miss critical indicators.
Fix: Position AI as a reconnaissance accelerator, not a decision engine. Require human validation of high-confidence findings. Use AI output to guide manual verification, not replace it.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Early Triage (Unknown Threat) | Sealed Read-Only AI | Minimizes mutation risk while accelerating evidence collection | Low compute, high forensic value |
| Deep Forensics (Confirmed Breach) | Manual + AI-Assisted Heavy Diagnostics | Requires operator approval for heap/memory captures to preserve stability | Moderate compute, high storage cost |
| Automated Containment (Post-Triage) | SOAR/EDR Playbooks | AI should not perform remediation; dedicated systems handle isolation safely | High automation, low manual overhead |
| Compliance Audit (Regulatory Review) | Immutable Audit Chain + Coverage Report | Provides verifiable evidence trail and explicit gap documentation | Low operational cost, high audit readiness |
Configuration Template
# investigation-policy.yaml
policy:
mode: read_only
blocked_actions:
- kill_process
- delete_file
- modify_registry
- restart_service
- block_ip
- disable_account
- install_agent
- edit_firewall
heavy_diagnostics:
require_approval: true
tools:
- heap_capture
- jfr_snapshot
- full_memory_dump
- kernel_trace
approval_timeout_seconds: 300
audit:
format: json
append_only: true
retention_days: 90
siem_forwarding: true
reporting:
include_coverage_gaps: true
include_policy_denials: true
output_formats:
- markdown
- json
Quick Start Guide
- Initialize the framework: Deploy the sealed tool registry, policy engine, audit logger, and heavy diagnostic gate as a single service or containerized module.
- Register investigation tools: Add read-only primitives for process inspection, network state, authentication logs, file metadata, and JVM diagnostics. Validate each tool against the read-only policy.
- Configure policy and gates: Load the YAML configuration to enforce mutation blocking and require explicit approval for heavy diagnostics. Verify audit logging is active and forwarding to centralized storage.
- Execute first triage plan: Feed the AI a weak clue (IP, process name, or log anomaly). The orchestrator will validate each step, execute approved tools, log results, and return a structured report with coverage gaps.
- Review and validate: Examine the audit chain, verify raw evidence artifacts, and cross-reference AI findings with manual inspection. Proceed to containment only after human validation.