Skip to content
Everything Agents

Lesson 10 of 14 · 5 min

Defense in depth

Schema descriptions, flag-based gates, server nonces, re-fetch on next action. Layer 2-3 anywhere stakes are real.

If @outputs.X can lie, the defense can't be a single setting. The playbook is layers. Use as many as the stakes warrant.

Defense in depthFour concentric layers between the language model's narration and the truth Apex actually produced. From outside in: schema descriptions, flag-based gates, server-issued nonces, and re-fetch on the next action.A · schema descriptionsB · flag-based gatesC · server-issued noncesD · re-fetch on next actionTRUTHLLM-SIDEnarration entersOUTERcheap, weakerspoofableINNERserver-enforcedhard to fakeouter layers narrow what reaches inner layers; inner layers are enforced by Apex

Defense A: schema descriptions narrow the prior

outputs:
    customer_id: string
        description: "Customer ID in the format cust_NNN (e.g. cust_100).
            Empty string means NOT verified. Never invent a value, use
            only what Apex returns."
    verified: string
        description: "The literal lowercase string 'true' or 'false'
            returned by Apex. Only 'true' means verified."

Defense B: gate on flags Apex controls, not on LLM-controlled values

Bad:

after_reasoning:
    if @variables.customer_id != "":          # any non-empty string passes
        set @variables.customer_verified = True

Better:

after_reasoning:
    if @variables.verified_flag == "true":
        set @variables.customer_verified = True

Best, because correlated values raise the bar for hallucination:

after_reasoning:
    if @variables.verified_flag == "true" and @variables.customer_id != "":
        set @variables.customer_verified = True

Defense C: server-issued nonces

Have Apex return a one-time token like "VRF-" + UUID. The LLM has no reason to invent a UUID-shaped string. Gate downstream actions on the token's presence.

public class ActionOutput {
    @InvocableVariable public String customer_id;
    @InvocableVariable public String verified;
    @InvocableVariable public String verification_token;  // fresh per call
}

Defense D: re-fetch on the next action

The next action down the pipeline (e.g. FindOrder) takes customer_id and re-validates it server-side. A hallucinated cust_999 fails the lookup. This is the strongest defense because it is implemented in Apex, not in the bundle.

Cost vs benefit

DefenseEffortSpoof difficulty for LLM
A. Output descriptionsTrivialSlightly harder
B. Apex-controlled flag gateSmallHarder
C. Server noncesMediumVery hard
D. Server-side re-fetchMedium-largeEffectively impossible

Apply A and B unconditionally. Apply C and D anywhere the action authorizes a downstream irreversible operation (refund, payment, data release).