CCDV-F · Security and Safety
Layered guardrails, least privilege and hooks that stop destructive actions
A public language tutor has a single defense: a system prompt that describes the policy and asks the model to refuse what’s inappropriate. Some accounts keep trying role-play tricks and sometimes get something. On another team, Claude Code ran a force push written as git push origin main -f, which no deny rule covered. Both cases share the same flaw: a single control, and a soft one.
Layered guardrails
No control is perfect, so you stack several independent ones. That’s guardrail layering:
| Layer | What it does |
|---|---|
| Input screen | A lightweight model (Haiku) classifies each message and returns a structured verdict before it reaches the main model |
| System prompt | Describes the content policy and what to do with a request outside it |
| Output validation | Checks the response before showing it or acting on it |
| Least privilege | The agent has no access to what it doesn’t need, so a mistake or a manipulation can’t do much damage |
| Monitoring | Logs refusals per account and throttles or suspends whoever keeps trying to bypass the policy |
Raising the temperature or using a larger model is not a layer: it controls nothing.
Secure by design
Secure by design decides access before the first prompt is written:
- The agent’s own identity and access: a read-only database role on the three views it needs, not the admin account with a “SELECT only” rule in the prompt.
- Privacy: personal data doesn’t enter the context if the task doesn’t need it.
- Isolation: code the model generates runs in an environment with no access to production.
- Human approval only where it matters: asking for confirmation on every query slows the work down, and people end up approving without reading.
Hooks for what must always or never happen
A hook is code the harness runs at a fixed point, without depending on the model remembering anything. In Claude Code it’s configured in settings.json (the project one is versioned and reviewed like code), and the Agent SDK offers the same events for your own applications.
The PreToolUse hook runs before every call and receives tool_name and tool_input, for example the full Bash command. It can block in two ways:
- exiting with exit code 2: the call is blocked and the stderr text reaches Claude as the reason; not even an
allowrule lets it through; - returning JSON with
permissionDecision: "deny"and a reason.
With a matcher (Bash, Edit|Write) you choose which tools it applies to. The hook can parse the command and recognize every variant of a force push or an rm -rf, something a list of exact strings in deny rules can’t do.
PostToolUse runs afterward: it’s useful for auditing, formatting or telling Claude about the result, but it can’t prevent something that already happened.
An instruction in CLAUDE.md or in the system prompt is guidance the model follows almost always. If something must never happen, it goes in a hook or a permission.
The usual traps
- A system prompt as the only defense.
- Asking users not to try tricks.
- Giving the agent the admin account and “asking” it not to write.
- Deny rules with every spelling of a command you can think of.
- Manual approval of every command instead of blocking what’s destructive.
- Repeating the rule in capital letters in CLAUDE.md.
On the exam
If the scenario has a single soft defense, look for the option that adds independent layers (pre-screening, monitoring, validation). If an agent has more access than it uses, look for a narrow role. And if there’s an action that must never happen in an agent with a terminal, look for a PreToolUse hook that blocks it.
Quick question
A practice exam question on this domain. It counts towards your progress.
A fitness company shipped a mobile app whose writing-coach feature calls the Claude API directly from the device. The API key is embedded in the app bundle so the feature could ship without a backend change, and the release went out in a hurry before a marketing campaign.
Two weeks later, usage on the key has tripled while daily active users stayed flat, and requests arrive from IP ranges the company does not recognize. The team cannot tell which requests come from real users and which do not, and the next campaign starts in a month.
What should the team do?