AFP engineering series · Chapter 24 of 25
Build privacy-conscious decision traces, containment controls, and evidence-driven recovery for LLM abuse and fraud incidents.
Log the decision chain, not every private conversation
An incident investigator needs to know what the user requested, what the model proposed, what policy decided, and what actually happened. Logging every raw prompt and tool result can expose personal data and secrets while still failing to capture the authoritative action state. Design telemetry around the decision chain first.
Use a shared request identifier, invocation identifier, proposal identifier, and operation identifier where appropriate. Keep their meanings distinct. One conversation may contain many proposed actions, and one action may involve several transport attempts. Correlation should reveal that structure rather than flatten it into a single chat log.
Define a minimal event schema
Illustrative python; adapt the persistence and identity adapters to your service.
event = {
"event_type": "action_denied",
"request_id": "synthetic-request-17",
"operation_id": "synthetic-operation-4",
"tool": "prepare_refund",
"policy_version": "refund-policy-7",
"reason_code": "tenant_mismatch",
"effect_committed": False,
"evidence_ref": "restricted-evidence-store/reference",
}
# No tokens, full payment details, or raw private document text here.Authenticate event producers and protect the log pipeline against tampering. Sanitize untrusted strings so they cannot forge log lines or inject misleading structure into dashboards. Use bounded field lengths and a schema that rejects unexpected data rather than serializing arbitrary exceptions.
The evidence reference should point to a controlled store with its own access policy and retention rules. Routine dashboards can show reason codes and counts without exposing the underlying sensitive material. Access to incident evidence should itself be audited.
Record attempted and committed effects separately
A model may propose an unauthorized tool call that the service rejects. That is different from a committed unauthorized action and should trigger a different severity. Conversely, a normal-looking model answer may conceal a dangerous tool effect. The service owning the resource must emit the authoritative completion event.
For streaming output, record whether any bytes were released before a block. For payments, record uncertain outcomes and reconciliation. For retrieval, record access scope and document identifiers without copying full contents. These details determine what containment and notification work is actually necessary.
Prepare scoped containment controls
| Control | Purpose |
|---|---|
| Disable one tool | Stop a harmful capability while preserving chat |
| Revoke one credential | Contain a compromised integration |
| Pause one tenant queue | Limit concentrated misuse |
| Quarantine a source version | Remove poisoned retrieval material |
| Freeze one operation family | Prevent repeated financial effects |
| Switch to approved static responses | Maintain limited service during screening outage |
Test that these controls take effect for queued and running work, not only new requests. A revoked tool should not remain usable through a cached capability list. Cancellation should stop new side effects while preserving enough state to reconcile operations already accepted by external systems.
Assign an owner and a documented reversal process to each control. An emergency pause that nobody knows how to remove can become a prolonged outage. Reinstatement should require evidence that the relevant invariant is restored, not merely that the alert volume dropped.
Run an evidence-first investigation
Start with confirmed effects and work backward through operation, policy, tool proposal, and source lineage. Determine which users, resources, and versions were exposed. Separate observed facts from hypotheses. A suspicious phrase in a prompt does not prove that it caused the outcome, and a model's explanation of its own behavior is not a forensic record.
Preserve a minimal reproducible fixture using synthetic replacements where possible. Keep original evidence restricted when needed for investigation. Record timestamps and clock sources so events from different services can be ordered reliably, and account for asynchronous delivery rather than assuming log arrival order equals execution order.
Repair the missing boundary and its derivatives
If a poisoned document caused the incident, invalidate its chunks, summaries, embeddings, and caches. If a tool lacked authorization, fix the service endpoint as well as the agent callback. If approval replay caused duplicate effects, reconcile the ledger and repair the state transition. A prompt wording change may be useful but should not substitute for the missing enforceable control.
Add a regression case that reproduces the failure and a legitimate neighboring case that must still succeed. Re-run the full affected workflow, including retries and recovery. Document what the test does not cover so the incident fix does not become an overbroad claim of safety.
Worked investigation: poisoned evidence leads to a denied action
An alert reports repeated unauthorized refund proposals after the assistant reads a supplier document. Begin with the action ledger: no refund committed. The policy logs show tenant mismatch denials. The model trace shows proposals influenced by a summary derived from source S12. This is a contained incident with a model and retrieval weakness, not confirmed financial loss.
Quarantine S12 and its derived summaries while preserving restricted evidence. Identify which conversations used those derivatives and inspect their actual outputs and tool effects. Do not assume every conversation was compromised, but do not stop at deleting the original document either. Cached summaries can continue carrying the influence.
The decision trace should link source version, model invocation, tool proposal, policy version, and operation result without exposing full customer records in the alert. Investigators with appropriate access can retrieve the evidence separately. This reduces the risk that the incident dashboard itself becomes a new disclosure channel.
Repair the missing boundary in source handling and add a regression fixture. Keep the backend ownership check that contained the event. If the team only changes the system prompt and removes the detector alert, it may lose visibility without fixing derivative provenance. Test source invalidation and clean legitimate summaries as part of the repair.
The post-incident record distinguishes observed facts, plausible mechanism, unresolved questions, and corrective actions. It includes time to quarantine, affected source versions, attempted actions, committed effects, and the evidence required for reinstatement. This disciplined accounting prevents both overclaiming harm and understating a real weakness. It also makes the event useful for improving AFP rather than merely producing another alarming chat transcript.
Measure readiness continuously
Track time to detect, time to contain, affected operations, evidence completeness, and recovery time. Practice with tabletop and sandbox drills. Verify that on-call staff can locate the right policy version and disable the relevant capability without searching through private conversation dumps.
OWASP's logging guidance provides general principles for sensitive data and event quality; this decision-chain design applies them to agent workflows. Good AFP observability makes harmful effects explainable and containable while minimizing the additional privacy risk created by the monitoring system itself.
Practice and continue
Open the interactive companion lab to inspect the assumptions and outcomes with synthetic data. Then return to the 25-chapter AFP learning path.
Sources and implementation scope
Primary references checked October 15, 2026. Framework details follow the linked documentation; the Northstar cases, policy contracts, and test designs are original illustrative designs. Python snippets labeled illustrative are not complete production integrations. ADK package metadata checked for this series reported 2.12.0; pin and test the version used by your application.