|
| 1 | +# Predicate Authority Demo: Hack vs Fix |
| 2 | + |
| 3 | +**See how Predicate Authority blocks prompt injection attacks in real-time.** |
| 4 | + |
| 5 | +This demo shows an AI agent attempting to: |
| 6 | +1. Read SSH private keys (blocked) |
| 7 | +2. Run `curl | bash` commands (blocked) |
| 8 | +3. Exfiltrate data to webhook.site (blocked) |
| 9 | +4. Read legitimate project files (allowed) |
| 10 | + |
| 11 | +## Quick Start |
| 12 | + |
| 13 | +```bash |
| 14 | +git clone https://github.com/PredicateSystems/openclaw-predicate-provider |
| 15 | +cd openclaw-predicate-provider/examples/demo |
| 16 | +./start-demo.sh |
| 17 | +``` |
| 18 | + |
| 19 | +That's it. Docker handles everything. |
| 20 | + |
| 21 | +## What You'll See |
| 22 | + |
| 23 | +``` |
| 24 | +┌───────────────────────────────────────────────────────────────┐ |
| 25 | +│ PREDICATE AUTHORITY DEMO: Hack vs Fix │ |
| 26 | +├───────────────────────────────────────────────────────────────┤ |
| 27 | +│ │ |
| 28 | +│ [1/3] UNGUARDED: SSH Key Exfiltration │ |
| 29 | +│ Action: fs.read │ |
| 30 | +│ Resource: ~/.ssh/id_rsa │ |
| 31 | +│ Source: untrusted_dm │ |
| 32 | +│ │ |
| 33 | +│ RESULT: SUCCESS (THIS IS BAD) │ |
| 34 | +│ Output: "-----BEGIN OPENSSH PRIVATE KEY-----..." │ |
| 35 | +│ │ |
| 36 | +│ [1/3] GUARDED: SSH Key Exfiltration │ |
| 37 | +│ Action: fs.read │ |
| 38 | +│ Resource: ~/.ssh/id_rsa │ |
| 39 | +│ Source: untrusted_dm │ |
| 40 | +│ │ |
| 41 | +│ DECISION: DENY (12ms) │ |
| 42 | +│ Reason: deny_sensitive_read_from_untrusted_context │ |
| 43 | +│ │ |
| 44 | +│ Attack blocked. Sensitive data protected. │ |
| 45 | +│ │ |
| 46 | +└───────────────────────────────────────────────────────────────┘ |
| 47 | +``` |
| 48 | + |
| 49 | +## How It Works |
| 50 | + |
| 51 | +``` |
| 52 | +┌─────────────┐ ┌──────────────┐ ┌─────────────┐ |
| 53 | +│ Agent │───▶│ Predicate │───▶│ Sidecar │ |
| 54 | +│ │ │ Provider │ │ (policy) │ |
| 55 | +│ fs.read │ │ │ │ │ |
| 56 | +│ ~/.ssh/... │ │ action:fs.read │ DENY │ |
| 57 | +└─────────────┘ │ source:untrusted └─────────────┘ |
| 58 | + └──────────────┘ |
| 59 | + │ |
| 60 | + ▼ |
| 61 | + ActionDeniedError |
| 62 | +``` |
| 63 | + |
| 64 | +1. Agent receives tool call request |
| 65 | +2. Provider intercepts and builds authorization request |
| 66 | +3. Sidecar evaluates policy rules |
| 67 | +4. Decision returned in <25ms |
| 68 | +5. DENY = throw error, ALLOW = execute |
| 69 | + |
| 70 | +## Key Properties |
| 71 | + |
| 72 | +| Property | Value | |
| 73 | +|----------|-------| |
| 74 | +| **Deterministic** | Policy-based rules, not probabilistic filtering | |
| 75 | +| **Fast** | p50 < 25ms authorization latency | |
| 76 | +| **Auditable** | Every decision logged with mandate ID | |
| 77 | +| **Fail-closed** | Sidecar errors block execution | |
| 78 | + |
| 79 | +## Customize the Policy |
| 80 | + |
| 81 | +Edit `policy.demo.json` to add your own rules: |
| 82 | + |
| 83 | +```json |
| 84 | +{ |
| 85 | + "rules": [ |
| 86 | + { |
| 87 | + "id": "deny_my_secrets", |
| 88 | + "effect": "deny", |
| 89 | + "action": "fs.*", |
| 90 | + "resource": ["**/secrets/*", "**/.env"], |
| 91 | + "reason": "deny_secrets_access" |
| 92 | + } |
| 93 | + ] |
| 94 | +} |
| 95 | +``` |
| 96 | + |
| 97 | +Then re-run `./start-demo.sh`. |
| 98 | + |
| 99 | +## Requirements |
| 100 | + |
| 101 | +- Docker (with Docker Compose) |
| 102 | + |
| 103 | +No other dependencies. Everything runs in containers. |
| 104 | + |
| 105 | +## Install in Your Project |
| 106 | + |
| 107 | +```bash |
| 108 | +npm install predicate-claw @predicatesystems/authorityd |
| 109 | +``` |
| 110 | + |
| 111 | +```typescript |
| 112 | +import { GuardedProvider, ToolAdapter } from "predicate-claw"; |
| 113 | + |
| 114 | +const provider = new GuardedProvider({ |
| 115 | + principal: "agent:my-agent", |
| 116 | +}); |
| 117 | + |
| 118 | +const adapter = new ToolAdapter(provider); |
| 119 | + |
| 120 | +// This will throw ActionDeniedError if policy denies |
| 121 | +await adapter.readFile({ |
| 122 | + args: { path: "~/.ssh/id_rsa" }, |
| 123 | + context: { source: "untrusted_dm" }, |
| 124 | + execute: async (args) => fs.readFile(args.path), |
| 125 | +}); |
| 126 | +``` |
| 127 | + |
| 128 | +## Links |
| 129 | + |
| 130 | +- [GitHub: openclaw-predicate-provider](https://github.com/PredicateSystems/openclaw-predicate-provider) |
| 131 | +- [npm: predicate-claw](https://www.npmjs.com/package/predicate-claw) |
| 132 | +- [npm: @predicatesystems/authorityd](https://www.npmjs.com/package/@predicatesystems/authorityd) |
| 133 | + |
| 134 | +## License |
| 135 | + |
| 136 | +MIT / Apache 2.0 |
0 commit comments