CapLite: Why Small Language Model Agents Can't Write Their Own Security Policies
Enforcement-based prompt injection defenses ask the agent's own language model to write a security artifact: a privilege policy, a dependency graph, a constraint list, or an executable program. Code then enforces that ar
Enforcement-based prompt injection defenses ask the agent's own language model to write a security artifact: a privilege policy, a dependency graph, a constraint list, or an executable program. Code then enforces that artifact. CaMeL, Progent, IPIGuard, and DRIFT all follow this pattern. The assumption is that the model understands the task well enough to generate a correct security boundary.
CapLite (arXiv:2611.17115v1) tests that assumption across 15 open-weight models, 13 of them between 1.7B and 12B parameters. The result: small language models cannot reliably write their own security policies. Attacks succeed against 14 models using Progent, 13 using IPIGuard, and 11 using DRIFT. CaMeL's generated programs fail to run in up to 68% of episodes.
The paper introduces a capability-based enforcement approach that does not ask the model to generate security artifacts at all. Instead, CapLite derives its policy from tool schemas, commits write calls before any tool result is read, and admits a write only if every argument that decides whom or what it affects appears in the user's request. This guarantees write integrity: injected text cannot add a write, and no write reaches a recipient, amount, object, or destination the user did not explicitly state.
The Model-Written Artifact Problem
Enforcement defenses treat the agent's model as both the task executor and the security policy author. The model generates a structured artifact that describes what the agent is allowed to do, then a separate enforcement layer checks every tool call against that artifact.
Failure modes when the model is too small:
- Incomplete policies: The model omits critical constraints, leaving gaps that attacks exploit.
- Contradictory constraints: The model writes rules that conflict, and the enforcement layer picks the permissive interpretation.
- Syntax errors: The generated artifact does not parse or execute, disabling enforcement entirely.
- Semantic drift: The model's understanding of the task shifts between artifact generation and tool invocation, creating a mismatch.
The paper tested this across four defenses:
| Defense | Artifact Type | Attack Success Rate (13 SLMs) | Failure Mode |
|---|---|---|---|
| Progent | Privilege policy | 14/15 models | Incomplete privilege declarations |
| IPIGuard | Dependency graph | 13/15 models | Missing or incorrect edges |
| DRIFT | Constraint list | 11/15 models | Contradictory or overly broad rules |
| CaMeL | Executable program | Up to 68% episode failures | Syntax errors, non-executable output |
The pattern is consistent: models below a certain capability threshold cannot generate security artifacts that enforcement code can trust.
CapLite's Capability-Based Architecture
CapLite removes the model from the security artifact generation loop. The enforcement policy is derived from tool schemas at initialization, not generated per-task.
Core enforcement rules:
- Schema-derived policy: Each tool's schema declares which arguments affect external state (recipients, amounts, destinations). The policy is built once from these declarations.
- Write-before-read: All write calls are committed before any tool result is read. This prevents an attacker from injecting a write after observing intermediate state.
- User-stated arguments: A write is admitted only if every argument that decides whom or what it affects is explicitly stated in the user's request. The enforcement layer parses the user's input and extracts entities, then checks each write call's arguments against that set.
Orchestration flow:
User request → Parse entities → Agent generates tool calls → Enforcement layer checks writes → Commit writes → Execute reads → Return results
The enforcement layer sits between the agent and the tool execution runtime. It does not ask the model to justify or explain its tool calls. It checks a simple invariant: did the user mention this recipient, amount, or destination?
Example enforcement check:
def admit_write(tool_call, user_entities):
"""
Admit a write only if all decision arguments appear in user_entities.
"""
decision_args = tool_call.schema.decision_arguments
for arg in decision_args:
if tool_call.args[arg] not in user_entities:
return False
return True
The user_entities set is extracted once from the user's request using a simple parser (regex or a small NER model). The decision_arguments list is declared in the tool schema. No model-generated artifact is involved.
Evaluation Results
CapLite was tested on AgentDojo, a benchmark with 13,935 attacked episodes. No attack succeeded. The defense guarantees write integrity: injected text cannot add a write, and no write reaches a recipient, amount, object, or destination the user did not state.
Utility and token efficiency:
| Defense | Utility Under Attack | Tokens per Episode | Utility per Token |
|---|---|---|---|
| CapLite | 29.0% | 17.1k | 1.70e-3 |
| CaMeL | 27.2% | 95.0k | 2.86e-4 |
| Progent | (not reported) | (not reported) | (not reported) |
| IPIGuard | (not reported) | (not reported) | (not reported) |
| DRIFT | (not reported) | (not reported) | (not reported) |
| Undefended | (not reported) | 20.0k | (not reported) |
CapLite uses 18% of CaMeL's tokens and achieves higher utility under attack. It also uses fewer tokens than the undefended agent, which suggests the enforcement overhead is minimal.
When Model-Written Artifacts Work
The paper does not identify a hard parameter threshold, but the pattern is clear: models above 12B parameters show better artifact quality, though still not perfect. The failure rate drops as model size increases, but even larger models occasionally generate incomplete or contradictory policies.
Factors that improve artifact reliability:
- Instruction-tuned models: Models fine-tuned for structured output (e.g., function calling, JSON generation) perform better.
- Explicit schema enforcement: If the artifact format is strictly validated before enforcement begins, syntax errors are caught early.
- Redundant checks: Generating multiple artifacts and voting or intersecting them reduces the chance of a single bad artifact.
None of these techniques eliminate the problem for SLMs. The cost of generating multiple artifacts or using a larger model for artifact generation alone often exceeds the cost of CapLite's schema-derived approach.
Deployment Constraints
CapLite's approach works when:
- Tool schemas are well-defined and include decision argument annotations.
- The user's request contains explicit entities (names, amounts, destinations).
- The task does not require the agent to infer implicit recipients or destinations.
Failure cases:
- Implicit references: If the user says "send it to my manager" without naming the manager, CapLite cannot extract the entity. The agent must resolve the reference before the write is admitted.
- Dynamic schemas: If tools are added or modified at runtime, the schema-derived policy must be regenerated.
- Complex state dependencies: If a write's validity depends on prior reads (e.g., "transfer the balance from account A to account B"), CapLite's write-before-read rule may block legitimate operations.
The paper does not address these cases in detail. The trade-off is clear: CapLite sacrifices flexibility for reliability. It works best in domains where the user's intent is explicit and the tool set is stable.
Security Boundary Comparison
| Approach | Policy Source | Enforcement Point | SLM Compatibility | Token Overhead |
|---|---|---|---|---|
| Model-written artifacts | Agent's own model | After artifact generation | Poor (14/15 fail) | High (95k) |
| Schema-derived (CapLite) | Tool schemas | Before tool execution | Good (0 attacks) | Low (17k) |
| Static allowlists | Developer-defined | Before tool execution | Excellent | Minimal |
| Runtime sandboxing | OS or container | During tool execution | Excellent | Variable |
Static allowlists and runtime sandboxing do not require the model to generate security artifacts, but they also do not adapt to the task. CapLite sits between these extremes: it adapts to the user's request without asking the model to write a policy.
Technical Verdict
Use CapLite when:
- You are deploying agents on small language models (under 12B parameters).
- Your tool schemas are stable and well-annotated with decision arguments.
- The user's requests contain explicit entities (names, amounts, destinations).
- You need prompt injection defense without the token overhead of model-written artifacts.
Avoid CapLite when:
- The user's requests rely on implicit references or context that the agent must resolve.
- Your tools are added or modified frequently, requiring policy regeneration.
- The task requires writes whose validity depends on prior reads (e.g., conditional transfers).
- You have access to a large model (70B+) that can reliably generate security artifacts.
The core insight is that enforcement defenses scale poorly to small models. If your deployment constraints push you toward SLMs, capability-based enforcement is a better fit than asking the model to write its own security policy.
Source Links
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.