Paladin sits between an AI agent and everything it touches, and decides each action before it happens.
This page is enough to evaluate it without talking to us. Everything here runs from the published package.
An agent asks to do something: call a model, call a tool, reach an MCP server, open a URL. Paladin sees that request first, evaluates it against your policy, and returns one of four decisions. Only then does the action run, or not.
The decision is deterministic. The same input gives the same decision, every time. There is no model in the enforcement path, so nothing guesses.
Everything runs inside your own infrastructure. Prompts, data, and models stay on your network.
pip install paladin-ai
One package. The engine ships compiled inside it, so there is no toolchain to install.
paladin up
That is the whole setup. On first boot Paladin writes a versioned policy store seeded with a safe baseline, generates an agent token, and opens a hash-chained audit log:
policy store at v1 (policy "paladin-recommended")
audit log: jsonl events.jsonl (hash-chained, tamper-evident)
agent token: auto-generated and saved
interceptor listening on 127.0.0.1:8080
It is enforcing from the first request. There is no monitor-only mode to forget to turn off.
Paladin installs into an agent's own hook mechanism where one exists, and falls back to running the agent behind a proxy where it does not. Your agent's code does not change.
| Agent | Command | What it covers |
|---|---|---|
| Claude Code | paladin install-hooks --agent claude | Every tool call |
| Codex CLI | paladin install-hooks --agent codex | Every tool call |
| Cursor | paladin install-hooks --agent cursor | Shell commands only |
| Anything else | paladin run -- <your command> | Model calls and egress through the proxy |
For Claude Code that is one command:
paladin install-hooks --agent claude
The installer merges into your existing settings. It preserves other hooks, refuses to touch a malformed file, and running it twice does nothing the second time.
From then on, every tool call is checked before it runs. A blocked call comes back with the reason:
Personal info detected in an outbound action; blocked from leaving.
Every rule resolves to exactly one of these.
In Claude Code an escalate decision becomes its own confirmation prompt, so a person approves in place. A redact decision blocks instead, because the hook protocol cannot rewrite arguments and quietly forwarding the original would be worse than stopping.
Policy is YAML. Rules are evaluated top to bottom and the first match wins. If nothing matches, the policy default applies. With no default set, Paladin denies.
version: "1.0"
id: "pii-egress-block"
name: "Block PII egress to external tools; mask PII to the model"
default_decision: allow
rules:
# PII must never leave through an external tool.
- id: "block-pii-external-data"
description: "Deny external-data calls whose payload contains PII."
when:
action_types: [tool_call, mcp_call]
targets: ["external-data"]
data_classes_any: ["pii.ssn", "pii.email", "pii.credit_card", "pii.phone"]
decision: deny
reason: "PII detected in a call to an external data tool; egress denied."
owasp: ["AAI-sensitive-information-disclosure", "AAI-excessive-agency"]
# Mask the most sensitive fields before the model ever sees them.
- id: "redact-pii-to-model"
description: "Redact SSNs and card numbers in prompts sent to the model."
when:
action_types: [model_call]
data_classes_any: ["pii.ssn", "pii.credit_card"]
decision: redact
reason: "High-sensitivity PII masked before reaching the model."
redact_classes: ["pii.ssn", "pii.credit_card"]
owasp: ["AAI-sensitive-information-disclosure"]
# Explicit catch-all, so the intent is auditable rather than implied.
- id: "allow-everything-else"
description: "Allow all other observed actions."
when: {}
decision: allow
reason: "No restriction matched."
A rule matches on the kind of action, the target it names, the classes of data found in it, and the state of the session it belongs to. Every rule carries a reason, which is the text a person sees when the action is stopped, and an optional OWASP tag that carries into reporting.
Apply a policy and read it back:
paladin policy apply my-policy.yaml
paladin policy show
paladin policy history
Policy changes take effect without a restart. Every version is kept.
Every decision is appended to a hash-chained log, so a record cannot be altered or removed without breaking the chain. Checkpoints over the chain are signed.
paladin audit verify
chain intact: every record connects to the one before it
OK: chain intact, all checkpoints verified
paladin up seeds a baseline called Recommended. It blocks personal information and credentials from leaving through a tool, asks for approval before data goes to an outside service, holds irreversible operations for a human, blocks content carrying a prompt injection, and tracks the combination of private data plus untrusted content plus an unapproved destination across a session.
What it does not cover, stated plainly. The baseline matches on tool names, targets, and the data found inside arguments. It does not match on arbitrary substrings of an argument. So a rule like "hold any shell command containing rm -rf" is not expressible today. For a coding agent, where every shell command arrives under a single tool name, the available lever is coarse: allow shell, or hold every shell command for approval. Argument-level matching and file-path awareness are the next things being built, and until they land this is a real limit rather than a configuration mistake.
Measured results, including the false-positive rate and the attacks that still get through, are on the benchmarks page.
Deployment topology, the Helm chart, credential brokering, multi-agent delegation, and the compliance and risk-graph reporting are covered in the material we share with design partners.
Cortexa Labs, Inc.