Your Agent Can Read Your Codebase But Can Never Touch Your Secrets
Your Agent Can Read Your Codebase But Can Never Touch Your Secrets
You''ve just connected your AI agent to the GitHub MCP. Suddenly it has access to 90+ tools: reading repos, creating PRs, triggering deployments, even executing arbitrary shell commands.
Here''s the uncomfortable truth: your agent can read everything and do almost anything. There''s no permission model. No allow-list. No rate limiting. Your agent connected to the wrong MCP is one prompt injection away from exfiltrating your .env file to a random Pastebin URL.
This is the problem Navil''s policy engine solves. With a single YAML file, you define exactly what tools your agents can call, what data they can access, and where they can send it.
The Problem: Agents as Skeleton Keys
Modern MCPs (Model Context Protocols) are powerful because they''re unconstrained. An agent with GitHub MCP access can:
- Read every file in your private repositories
- Create and merge pull requests
- Trigger CI/CD pipelines
- Execute shell commands in your infrastructure
- Modify secrets and environment variables
The model hasn''t done anything wrong. The MCP integration hasn''t done anything wrong. But there''s a gap in the architecture: the agent has capabilities, but no guardrails tell it which capabilities are safe to use.
When you ask an agent to "review my code," it should read files and create comments--not write to .env or execute rm -rf. When you ask it to "check deployment status," it should query APIs--not trigger production deployments.
Without a policy layer, you''re trusting the model to guess your security boundaries. That''s a bet you shouldn''t make.
The Solution: Navil''s Policy Engine
Navil introduces a declarative policy layer that sits between your agent and every tool call. Before an action executes, Navil evaluates it against your policy. Blocked actions fail explicitly with a clear error message--nothing happens silently.
The default is permissive: allow: "*" means nothing changes unless you opt in. But once you define a policy, Navil enforces it at every decision point.
Policies control five dimensions:
1. Tool Allow-Lists
Specify which tools agents can call. A code-review agent only needs get_pull_request, list_files, and create_review_comment--nothing else.
2. Path-Based Restrictions
Block writes to sensitive files: .env, .ssh, *.pem, *.key. Agents can read your codebase, but secrets remain read-only.
3. Domain-Based Blocking
Restrict where http_request tools can send data. Block exfiltration endpoints: Pastebin, ngrok, Discord webhooks, random S3 buckets.
4. Per-Agent Rate Limiting
Set rate limits on dangerous tools. shell_exec max 20 invocations per day. http_request max 100 per minute. Prevents resource exhaustion and runaway loops.
5. Data-Sensitivity Gates Declare which fields in your config are sensitive. Agents can reference them in code paths but never transmit them externally.
A Real Policy Example
Here''s what a production policy looks like:
scopes:
code-review:
allow: [get_pull_request, list_files, create_review_comment]
deploy:
allow: [create_deployment, get_deployment_status, list_deployment_logs]
default:
allow: "*"
rules:
- action: deny
tools: [fs_write, shell_exec]
paths: [".env", "*.pem", "~/.ssh/*", ".secrets", "*.key"]
reason: "Secrets are read-only"
- action: deny
tools: [http_request]
domains: ["*.pastebin.com", "*.ngrok.io", "*.webhook.site", "discord.com/api/webhooks/*"]
reason: "Block known exfiltration endpoints"
- action: allow
tools: [shell_exec]
rate_limit: 20/day
reason: "Shell execution limited to prevent resource exhaustion"
- action: allow
tools: [http_request]
rate_limit: 100/min
reason: "General rate limit on outbound requests"
sensitive_fields:
- database_password
- api_key
- stripe_secretThis policy achieves several goals:
- The
code-reviewscope restricts tools to read-only PR operations - The
deployscope allows deployment operations but with no file writes - All agents inherit the
defaultscope (full access) unless scoped differently - File writes to secret files are globally denied
- HTTP requests to exfiltration endpoints are blocked
- Shell execution is rate-limited to 20 calls per day
- Sensitive fields are declared so Navil can apply extra scrutiny
How to Apply Your Policy
Once you''ve written your policy file, apply it when wrapping your agent config:
navil wrap config.json --policy policy.yamlNavil injects policy enforcement into your agent initialization. Every tool call goes through the policy engine before execution. If a tool call violates the policy, the agent receives a clear error:
ToolCallError: Tool ''fs_write'' denied for path ''.env''
Reason: Secrets are read-only
Allowed paths: [src/*, tests/*, docs/*]
The agent sees the error and can adjust its behavior. It doesn''t silently fail. It doesn''t retry in a loop. It gets actionable feedback.
How It Works Under the Hood
Navil''s policy engine runs as a proxy layer written in Rust. When you deploy an agent, policy evaluation happens at the policy gateway before any tool receives the request.
The execution flow:
- Agent decides to call tool X with parameters P
- Request hits Navil policy gateway
- Gateway parses the tool name, parameters, and agent context
- Policy matcher evaluates rules in order:
- Does the agent''s scope allow this tool?
- Do the parameters violate path restrictions?
- Does the domain match a blocked list?
- Has the agent exceeded rate limits?
- If all checks pass: request is forwarded to the tool
- If any check fails: agent receives a
ToolCallError
This happens in sub-microsecond time using O(1) Redis lookups for:
- Tool allow-lists (hash lookup)
- Path matchers (regex cache, evaluated once)
- Domain matchers (suffix tree, O(1) worst case)
- Rate limit counters (atomic increments)
The overhead is negligible. You get security without latency.
Token Scoping + Policy Engine = Complete Control
Navil has two complementary security layers:
Token Scoping (from our previous post) controls what agents see. If you scope a token to read-only GitHub access, the agent never sees deployment tools.
Policy Engine controls what agents can do. Even if an agent can see shell_exec, your policy can deny it on sensitive paths.
Together, they form defense-in-depth:
Visibility Layer (Token Scoping)
↓
What tools are available?
Only tools the agent''s token permits
↓
Execution Layer (Policy Engine)
↓
What can this tool actually do?
Only actions the policy permits
A well-secured agent has both layers active. Token scoping prevents the agent from seeing dangerous tools. Policy rules prevent the agent from misusing tools it can see.
What Happens When a Tool Call Is Blocked
Blocking is explicit, never silent.
When an agent attempts to call a denied tool, it receives:
{
"error": "ToolCallError",
"tool": "fs_write",
"reason": "Blocked by policy: Secrets are read-only",
"allowed_tools_for_scope": ["get_file", "read_directory"],
"contact": "security@navil.ai"
}The agent sees this error and can decide how to respond: use a different tool, ask the user, or escalate the request. The error is informative, not a black box failure.
Rate limit violations are similar:
{
"error": "RateLimitExceeded",
"tool": "shell_exec",
"limit": "20 per day",
"used": 20,
"reset_at": "2026-03-26T00:00:00Z",
"message": "Daily shell_exec quota exhausted. Try again tomorrow."
}Getting Started
Define your policy in policy.yaml. Keep it next to your agent config:
scopes:
default:
allow: "*"
rules:
- action: deny
tools: [fs_write, shell_exec]
paths: [".env", "*.key", "*.pem"]
reason: "Secrets are read-only"Apply it:
navil wrap config.json --policy policy.yaml --deployVerify the policy is active:
navil policy status config.jsonView your current policy:
navil policy show config.jsonUpdate your policy anytime without restarting agents:
navil policy update config.json --policy policy.yamlPolicies are hot-reloaded. Changes take effect within seconds.
Next Steps
Start with a permissive policy and tighten over time. Document why each rule exists. Review your policy quarterly as your agent''s responsibilities grow.
The policy engine is the first step toward agents you can trust. It''s not perfect--policy isn''t a replacement for code review, audit logging, or human oversight--but it''s a massive step forward from "hope the model plays nice."
Ready to make your agents secure?
pip install navilThen check out the policy reference and examples.
Next in the series: "Audit Logging--Who Did What, and Why"
Get your coverage score
See how well your AI agents are protected against known threats.