Lesson 6: Fix a Finding With a Fact
Training overview · Lesson 6 of 11 · Previous: State what the agent can do · Next: Record a compensating control
Goal
A fix changes a fact. It breaks a finding only by making one of its required legs absent. (A finding also falls below the bar when fewer than two of its required legs are present, as lesson 2's exercise shows, but that is a missing fact, not a fix.)
After this lesson you can read a fix on a finding, tell whether it breaks the finding, and record it in the model once it is true.
What you start from
Your model from lesson 5, or import L5-solution.zip.
The recipe step
This lesson uses the same step as lesson 5. This time the answer changes because the system changed.
Step 5: State what the agent can do
Answer the element facts the drawing cannot show: what the agent's tools can do and whether they need approval, the harness approval mode, egress restrictions, and who can write to each store. A yes-or-no field offers Yes, No and Not answered; it starts at Not answered, and choosing Not answered takes an answer back.
Why: Whether an agent can act on what it reads, and whether anything stops it, is not visible in a drawing.
Ask:
- Can the agent's tools change anything outside the conversation: send, post, update, delete, pay?
- Does every such action need a person's approval?
- Can the agent run code?
- Is the agent's network egress limited to an allowlist?
- Are the agent's tool credentials limited to the user it acts for?
- Does the chat frontend render images or links in model output?
Looks safe is the answer a guess would pick. Write it only when someone who knows has said so.
| On | Field | Looks safe | What it decides |
|---|---|---|---|
| Agent Service | Consequential Tools Present (consequential_tools_present, under Human Oversight) | false | Whether the agent can act at all; whether it holds tools that act |
| Agent Service | All Consequential Action Paths Require Approval (consequential_tools_all_require_approval, under Human Oversight) | true | Whether its actions wait for a person |
| Agent Service | Approval Gate Present (approval_gate_present, under Human Oversight) | — | Whether its actions wait for a person |
| Agent Chat Frontend | All Consequential Actions Require Blocking In-Chat Approval (consequential_tools_all_require_approval, under Authorization & RBAC) | true | Whether its actions wait for a person |
| Untrusted Content Source | Human Approval for High-Risk Actions (human_approval_for_high_risk_actions, under Authorization & RBAC) | required | Whether its actions wait for a person |
| Agent Code Execution Sandbox | Consequential Computer-Use Actions Confirmed (computer_use_consequential_actions_confirmed, under Computer Use) | true | Whether its actions wait for a person |
| Agent Service | Code Execution Tools Present (code_execution_tools_present, under Application Security) | false | Whether it can run code; whether it holds tools that act |
| Local MCP Server, Remote MCP Server | Destructive Tools Exposed (destructive_tools_exposed, under Authorization & RBAC) | false | Whether it holds tools that act |
| Agent Service | Network Egress Default-Deny Allowlist (network_egress_default_deny_allowlist, under Network & Connectivity) | true | Whether a way out is closed |
| Agent Tool Call | Agent Egress Restricted (agent_egress_restricted, under Network & Connectivity) | true | Whether a way out is closed |
| Agent Harness | Network Egress Default-Deny Allowlist (network_egress_default_deny_allowlist, under Network & Connectivity) | true | Whether a way out is closed |
| Local MCP Server | Server Network Egress Restricted (server_network_egress_restricted, under Data Handling & Residency) | true | Whether a way out is closed |
| Agent Chat Frontend | Markdown Image Rendering Policy (markdown_image_rendering_policy, under Output Rendering Exfiltration) | disabled, allowlisted_trusted_domains_only | Whether a way out is closed |
| Agent Harness | Harness Approval Mode (harness_approval_mode, under Authorization & RBAC) | default, plan (on-request, granular: the agents' own approval answers decide) | How the harness approves actions |
| Agent Harness | All-Approvals-Off Launch Flags in Use (dangerously_skip_permissions_in_use, under Authorization & RBAC) | false | A switch that skips approval whatever the mode |
| Context Ingress | Human Approval for Actions After Untrusted Ingress (human_approval_for_actions_after_untrusted_ingress, under Authorization & RBAC) | true | Whether a path into an action waits for a person |
| Context Ingress | Untrusted Ingress Can Trigger Consequential Actions (untrusted_ingress_can_trigger_consequential_actions, under Authorization & RBAC) | false | Whether a path into an action waits for a person |
| Agent Tool Call | Human Approval for Sensitive Tool Calls (human_approval_for_sensitive_tool_calls, under Authorization & RBAC) | true | Whether a path into an action waits for a person |
| Agent Service | Tool Credentials Least Privilege in User Context (tool_credentials_least_privilege_user_context, under Authorization & RBAC) | true | Whether the agent's tool credentials are limited to the user it acts for |
| Vector Database | Authentication Required for Every Request (authentication_required, under Authentication & Access) | true | Who can write to a store the agent reads |
| Vector Database | Writes Restricted to Ingestion Pipeline (index_write_restricted_to_pipeline, under Data Integrity) | true | Who can write to a store the agent reads |
| Vector Database | API Not Publicly Reachable (not_publicly_reachable, under Network & Connectivity) | true | Who can write to a store the agent reads |
| Agent Memory Service | Memory Writes Gated From Untrusted Content (memory_write_gated_from_untrusted_content, under Memory Integrity) | true | Who can write to a store the agent reads |
| Agent Memory Service | Memory Endpoints Require Authentication (memory_endpoints_require_authentication, under Authentication & Access) | true | Who can write to a store the agent reads |
| Agent Credential | Credential Expiry Enforced (credential_expiry_enforced, under Secrets & Credentials) | true | How strong a credential is |
| Agent Credential | Key Rotation Enabled (key_rotation_enabled, under Secrets & Credentials) | true | How strong a credential is |
| Agent Credential | Resource Scope Restricted (resource_scope_restricted, under Authorization & RBAC) | true | How strong a credential is |
| Agent Credential | Permission Scope Minimized (permission_scope_minimized, under Authorization & RBAC) | true | How strong a credential is |
| Agent Tool Call | Handoff Permission Mode Not Widened (handoff_permission_mode_not_widened, under Authorization & RBAC) | true | Whether a hand-off widens the permissions |
| Agent Server | Server Secrets Readable by Tool Code (server_secrets_readable_by_tool_code, under Secrets & Credentials) | false | Whether tool code can read the server's secrets |
| Agent Server | Runtime API Authentication Enforced (api_authentication_enforced, under Authentication & Access) | true | How an outsider gets a first foothold |
| Langflow | Custom Components Allowed (allow_custom_components, under Code Execution) | false | How an outsider gets a first foothold |
| Langflow | Auto-Login Enabled (langflow_auto_login, under Authentication & Access) | false | How an outsider gets a first foothold |
| Local MCP Server | Launcher Package Version Pinned (launcher_package_version_pinned, under Supply Chain Integrity) | true | How an outsider gets a first foothold |
| Local MCP Server | Server Package Provenance Vetted (server_package_provenance_vetted, under Supply Chain Integrity) | true | How an outsider gets a first foothold |
| Local MCP Server | mcp-remote Bridge Used (mcp_remote_bridge_used, under Application Security) | false | How an outsider gets a first foothold |
| Local MCP Server | mcp-remote Version Patched (mcp_remote_version_patched, under Application Security) | true | How an outsider gets a first foothold |
| Harness approval mode | The agent it runs |
|---|---|
default | waits for approval |
plan | waits for approval |
acceptEdits | acts without approval |
auto | acts without approval |
dontAsk | acts without approval |
bypassPermissions | acts without approval |
never | acts without approval |
on-request | does not decide: also answer the agent's own approval facts |
granular | does not decide: also answer the agent's own approval facts |
Steps
Read the fix. In the Threat Patterns analysis, open the Findings tab and expand Injection to action at the support copilot. Read its Fixes. The fix Require a person's approval before the agent's write calls and code runs, or a content-aware tool authorisation policy lands on the copilot, its owner is the operator of the agent, and it reads breaks this finding alone.
Below the fixes, lines such as untrusted_input own (Context Ingress: ticket): the pack has no fix for this route mean that the untrusted input leg cannot be cut on that route. A fix on another required leg, like this one on no gate, still breaks the finding.
Record the change once it is true. The team takes the fix: from now on, a staff member approves every reply before the copilot posts it. Only now, with the change made and confirmed, record it in the model:
- On Support copilot, set All Consequential Action Paths Require Approval (
consequential_tools_all_require_approval, under Human Oversight) =true.
Generate again.
What you should see
Findings: 1 systemic finding: 1 Confirmed · 0 Not ruled out.
| Finding | State | Legs |
|---|---|---|
| Lethal trifecta at Support copilot | Confirmed · unmitigated | U present · P present · X present · W absent (aggravating) |
Facts to establish: 1 question.
Facts that could raise a finding:
- Draw the Agent Tool Call from Support copilot to the harness that reads files for it, if there is one
Model gaps: No gaps these patterns can detect; not an attestation of completeness.
Injection to action is gone. The lethal trifecta stays Confirmed, with W now absent.
What changed and why
No gate became absent. The copilot's consequential tools all need approval now. The no gate leg of injection to action is absent, and one absent required leg means no finding. That is what breaks this finding alone promised.
It does not come back as a question. Injection to action does not reappear under Facts that could raise a finding. No required leg is left undetermined, so there is nothing to ask.
The trifecta stays. Approval changed W, and W is aggravating on the trifecta: it never decides it. U, P and X are still present. To break the trifecta, one of those three has to become absent, for example by cutting every way out, including the ones still open as to settle: lines in the X leg.
Every path must be approved. The field says all consequential action paths. The analysis treats an agent as gated by approval only when every path into an action is approved; one path that skips approval leaves the gate open.
Approval counts only if it is real. Before you record approval as true, check three things with the team:
- The approver sees the real action: the full arguments and links of the call, not a summary the agent wrote.
- The review screen loads no remote content. A screen that renders images or links from the action can itself send data out before anyone clicks.
- Turning approval off raises an alert. Otherwise one configuration change removes the gate without anyone noticing.
The fix was true. You set the value because the team made the change and told you so. Lesson 8 shows the same edit made without anyone saying so, and why that is not a fix.
Exercise: Egress instead of approval
Try another fix instead of approval, on a scratch copy of lesson 5's solution. Make this change and generate again:
On a scratch copy: import L5-solution.zip and rename it.
- On Support copilot, set Network Egress Default-Deny Allowlist (
network_egress_default_deny_allowlist, under Network & Connectivity) =true.
Findings: 2 systemic findings: 2 Confirmed · 0 Not ruled out.
| Finding | State | Legs |
|---|---|---|
| Lethal trifecta at Support copilot | Confirmed · unmitigated | U present · P present · X present · W present (aggravating) |
| Injection to action at Support copilot | Confirmed · unmitigated | untrusted input present · action tools present · no gate present · sensitive target present (aggravating) · broad identity undetermined (aggravating) |
Facts to establish: 1 question.
Facts that could raise a finding:
- Draw the Agent Tool Call from Support copilot to the harness that reads files for it, if there is one
Model gaps: No gaps these patterns can detect; not an attestation of completeness.
Nothing breaks. Expand the trifecta and look at the X leg's routes. The copilot's own way out stays present, with a conflict note on its route line: the drawing still shows the fetch reaching the internet. A drawn flow beats an egress attribute.
Do not delete the fetch flow because someone says "allowlist". An allowlist closes a way out only if no outsider can read or write any destination on it. Many allowed destinations fail that test: file-sharing hosts, proxies, content delivery networks, sites with open redirects, and your own ticket or e-mail channel. Public incidents such as EchoLeak, ForcedLeak and CamoLeak moved data out through destinations that were allowed. So when the team says the egress is allowlisted, ask for the list. Keep every allowed destination an outsider can read or write drawn, in its true zone. Replace the flow to Arbitrary internet hosts only when someone who knows confirms that no destination on the list is open to outsiders.
Count the routes. Even a perfect allowlist leaves the reply e-mail: the copilot's reply still reaches the customer through the ticket system.
Injection to action stays Confirmed too: egress says nothing about whether actions are approved.
Delete the copy when you are done.
Next
Lesson 7: Record a compensating control. You add a control to the copilot and see what it does to the trifecta, and what it does not.
