|
1 | | -# Hornet |
| 1 | +# 🐝 Hornet |
2 | 2 |
|
3 | | -Autonomous coding agent running as an isolated Linux user. |
| 3 | +**Hardened autonomous agent infrastructure. Careful — you might get stung.** |
4 | 4 |
|
5 | | -## Architecture |
6 | | - |
7 | | -``` |
8 | | -hornet_agent (uid) |
9 | | -├── ~/.config/.env # secrets (not in repo) |
10 | | -├── ~/.ssh/ # SSH key for GitHub (not in repo) |
11 | | -├── ~/.pi/agent/ |
12 | | -│ ├── settings.json # pi config |
13 | | -│ ├── skills/ → ~/hornet/pi/skills/ |
14 | | -│ └── extensions/ → ~/hornet/pi/extensions/ |
15 | | -├── ~/hornet/ # this repo |
16 | | -│ ├── start.sh # launch script |
17 | | -│ ├── setup.sh # install from scratch |
18 | | -│ ├── SECURITY.md # trust boundaries & threat model |
19 | | -│ ├── hooks/ |
20 | | -│ │ └── pre-commit # self-modification guardrail (installed root-owned) |
21 | | -│ ├── bin/ # security scripts (all protected) |
22 | | -│ │ ├── hornet-docker # Docker wrapper (blocks escalation) |
23 | | -│ │ ├── hornet-safe-bash # Bash wrapper (blocks dangerous commands) |
24 | | -│ │ ├── harden-permissions.sh # Lock down pi state files |
25 | | -│ │ ├── security-audit.sh # 24-check security audit |
26 | | -│ │ ├── scan-extensions.mjs # Cross-pattern static analysis |
27 | | -│ │ ├── setup-firewall.sh # Port-based network lockdown |
28 | | -│ │ └── redact-logs.sh # Secret scrubber for session logs |
29 | | -│ ├── slack-bridge/ |
30 | | -│ │ ├── bridge.mjs # Slack ↔ pi bridge (Socket Mode) |
31 | | -│ │ ├── security.mjs # Security functions (protected) |
32 | | -│ │ └── package.json |
33 | | -│ └── pi/ |
34 | | -│ ├── settings.json |
35 | | -│ ├── skills/ |
36 | | -│ │ ├── control-agent/SKILL.md |
37 | | -│ │ ├── dev-agent/SKILL.md |
38 | | -│ │ └── sentry-agent/SKILL.md |
39 | | -│ └── extensions/ |
40 | | -│ ├── tool-guard.ts # Tool call interception (protected) |
41 | | -│ ├── sentry-monitor.ts # Sentry API integration |
42 | | -│ ├── zen-provider.ts # OpenCode Zen LLM provider |
43 | | -│ ├── auto-name.ts # Session naming via env var |
44 | | -│ ├── control.ts, context.ts, files.ts, loop.ts, todos.ts |
45 | | -│ ├── agentmail/, email-monitor/, kernel/ |
46 | | -│ └── ... |
47 | | -├── ~/workspace/ # project repos + worktrees |
48 | | -│ ├── modem/ # product app |
49 | | -│ ├── website/ # marketing site |
50 | | -│ └── worktrees/ # git worktrees for dev-agent branches |
51 | | -└── ~/scripts/ # agent-authored operational scripts |
52 | | -``` |
| 5 | +Hornet is an open framework for running AI coding agents as isolated Linux processes with defense-in-depth security. It assumes the worst: that the agent *will* be prompt-injected, and builds kernel-level walls that hold even when the LLM is fully compromised. |
53 | 6 |
|
54 | | -## Identity |
| 7 | +## Why |
55 | 8 |
|
56 | | -| | | |
57 | | -|---|---| |
58 | | -| **Unix user** | `hornet_agent` | |
59 | | -| **GitHub** | [hornet-fw](https://github.com/hornet-fw) | |
60 | | -| **Email** | hornet@modem.codes → hornet@agentmail.to | |
61 | | -| **LLM** | Claude Opus 4.6 via OpenCode Zen | |
62 | | -| **Pi agent** | control-agent (spawns dev-agent + sentry-agent) | |
| 9 | +Every AI agent framework gives the model shell access and hopes for the best. Hornet doesn't hope — it enforces: |
63 | 10 |
|
64 | | -## Security |
| 11 | +- **OS-level isolation** — dedicated Unix user, no sudo, can't see other processes |
| 12 | +- **Kernel-enforced network control** — iptables per-UID egress allowlist |
| 13 | +- **Tamper-proof security** — root-owned hooks prevent the agent from weakening its own defenses |
| 14 | +- **Dual-layer command blocking** — dangerous shell patterns caught before execution at two independent layers |
| 15 | +- **Self-healing** — permissions hardened on every boot, secrets redacted from logs automatically |
65 | 16 |
|
66 | | -See [SECURITY.md](SECURITY.md) for full trust boundaries and threat model. |
| 17 | +## Security Stack |
67 | 18 |
|
68 | | -- Runs as unprivileged `hornet_agent` user — no sudo |
69 | | -- Cannot read admin home directory |
70 | | -- Docker access via wrapper that blocks privilege escalation |
71 | | -- External content (Slack, email) wrapped with security boundaries before reaching LLM |
72 | | -- Prompt injection detection logging in the Slack bridge |
73 | | -- Secrets in `~/.config/.env` (600 perms, not in repo) |
74 | | -- SSH key owner-only (700/600 perms) |
75 | | -- **Self-modification guardrails**: root-owned pre-commit hook + tool-guard rules prevent agent from weakening its own security tooling |
| 19 | +| Layer | What | Survives prompt injection? | |
| 20 | +|-------|------|---------------------------| |
| 21 | +| **iptables egress** | Per-UID firewall chain. Allowlisted ports only, no listeners, no reverse shells. | ✅ Kernel-enforced | |
| 22 | +| **Process isolation** | `/proc` mounted `hidepid=2`. Agent can't see other PIDs. | ✅ Kernel-enforced | |
| 23 | +| **Self-modification guard** | Root-owned pre-commit hook + tool-guard extension. Agent can't edit security files. | ✅ Root-owned | |
| 24 | +| **Shell deny list** | `hornet-safe-bash` blocks rm -rf, reverse shells, fork bombs, curl\|sh. Root-owned. | ✅ Root-owned | |
| 25 | +| **Tool call interception** | Pi extension blocks dangerous tool calls before they hit disk or shell. | ✅ Compiled into runtime | |
| 26 | +| **Content wrapping** | External messages wrapped with security boundaries + Unicode homoglyph sanitization. | ⚠️ LLM-dependent | |
| 27 | +| **Injection detection** | 12 regex patterns flag suspicious content. Log-only. | ⚠️ Detection, not prevention | |
| 28 | +| **Filesystem hardening** | 700 dirs, 600 secrets, enforced on every boot. | ✅ Cron/boot script | |
| 29 | +| **Log redaction** | Scrubs API keys, tokens, private keys from session logs. | ✅ Boot script | |
| 30 | +| **Extension scanning** | Static analysis for exfiltration, obfuscation, crypto-mining patterns. | ✅ Audit-time | |
76 | 31 |
|
77 | | -### Security Scripts |
| 32 | +**202 tests** across 6 test suites. CI runs all tests + `detect-secrets` on every push. |
78 | 33 |
|
79 | | -```bash |
80 | | -# Check security posture |
81 | | -~/hornet/bin/security-audit.sh |
82 | | - |
83 | | -# Lock down pi state file permissions (run on startup) |
84 | | -~/hornet/bin/harden-permissions.sh |
| 34 | +## Architecture |
85 | 35 |
|
86 | | -# Apply port-based network restrictions (run as root) |
87 | | -sudo ~/hornet/bin/setup-firewall.sh |
| 36 | +``` |
| 37 | +hornet_agent (unprivileged uid) |
| 38 | +│ |
| 39 | +├── ~/hornet/ ← this repo |
| 40 | +│ ├── bin/ ← 🔒 security scripts (all root-protected) |
| 41 | +│ │ ├── security-audit.sh 24-check security audit |
| 42 | +│ │ ├── setup-firewall.sh iptables per-UID lockdown |
| 43 | +│ │ ├── hornet-safe-bash shell command deny list |
| 44 | +│ │ ├── hornet-docker Docker wrapper (blocks escalation) |
| 45 | +│ │ ├── harden-permissions.sh filesystem hardening |
| 46 | +│ │ ├── scan-extensions.mjs extension static analysis |
| 47 | +│ │ └── redact-logs.sh secret scrubber for logs |
| 48 | +│ ├── hooks/pre-commit ← 🔒 self-modification guardrail |
| 49 | +│ ├── pi/extensions/ |
| 50 | +│ │ ├── tool-guard.ts ← 🔒 tool call interception |
| 51 | +│ │ └── ... agent-modifiable extensions |
| 52 | +│ ├── pi/skills/ agent-modifiable operational knowledge |
| 53 | +│ ├── slack-bridge/ |
| 54 | +│ │ ├── bridge.mjs Slack ↔ agent bridge |
| 55 | +│ │ └── security.mjs ← 🔒 content wrapping, rate limiting, auth |
| 56 | +│ ├── setup.sh ← 🔒 system setup (creates user, firewall, etc.) |
| 57 | +│ └── SECURITY.md ← 🔒 threat model |
| 58 | +│ |
| 59 | +├── ~/workspace/ project repos + git worktrees |
| 60 | +└── ~/.config/.env secrets (600 perms, not in repo) |
88 | 61 | ``` |
89 | 62 |
|
90 | | -## Setup |
| 63 | +🔒 = protected by root-owned pre-commit hook + tool-guard rules. Agent cannot modify. |
| 64 | + |
| 65 | +## Quick Start |
91 | 66 |
|
92 | 67 | ```bash |
93 | | -# Clone the repo (need SSH key + known_hosts first) |
94 | | -sudo su - hornet_agent -c 'ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null' |
| 68 | +# Clone |
95 | 69 | sudo su - hornet_agent -c 'git clone git@github.com:modem-dev/hornet.git ~/hornet' |
96 | 70 |
|
97 | | -# Run setup (as root) |
| 71 | +# Setup (creates user, firewall, permissions — run as root) |
98 | 72 | sudo bash /home/hornet_agent/hornet/setup.sh <admin_username> |
99 | 73 |
|
100 | 74 | # Add secrets |
101 | 75 | sudo su - hornet_agent -c 'vim ~/.config/.env' |
102 | | -# GITHUB_TOKEN=... |
103 | | -# OPENCODE_ZEN_API_KEY=... |
104 | | -# AGENTMAIL_API_KEY=... |
105 | | -# KERNEL_API_KEY=... |
106 | | -# HORNET_SECRET=... |
107 | | -# SLACK_BOT_TOKEN=xoxb-... |
108 | | -# SLACK_APP_TOKEN=xapp-... |
109 | | -# SLACK_ALLOWED_USERS=U01234,U56789 |
110 | | -# SENTRY_AUTH_TOKEN=... |
111 | | -# HORNET_ALLOWED_EMAILS=you@example.com |
112 | | -``` |
113 | 76 |
|
114 | | -## Launch |
115 | | - |
116 | | -```bash |
| 77 | +# Launch |
117 | 78 | sudo -u hornet_agent /home/hornet_agent/hornet/start.sh |
118 | 79 | ``` |
119 | 80 |
|
120 | | -This starts the **control-agent**, which automatically spawns a **dev-agent** and **sentry-agent** in tmux sessions, and starts the Slack bridge. |
121 | | - |
122 | | -## Monitoring |
123 | | - |
124 | | -Hornet uses tmux to manage sub-agent sessions. All commands run as `hornet_agent`. |
| 81 | +## Configuration |
125 | 82 |
|
126 | | -### List sessions |
| 83 | +Secrets live in `~/.config/.env` (not in repo, 600 perms): |
127 | 84 |
|
128 | 85 | ```bash |
129 | | -sudo -u hornet_agent tmux ls |
| 86 | +GITHUB_TOKEN=... |
| 87 | +OPENCODE_ZEN_API_KEY=... |
| 88 | +SLACK_BOT_TOKEN=xoxb-... |
| 89 | +SLACK_APP_TOKEN=xapp-... |
| 90 | +SLACK_ALLOWED_USERS=U01234,U56789 # fail-closed: bridge exits if empty |
| 91 | +AGENTMAIL_API_KEY=... |
| 92 | +KERNEL_API_KEY=... |
| 93 | +SENTRY_AUTH_TOKEN=... |
| 94 | +HORNET_SECRET=... |
| 95 | +HORNET_ALLOWED_EMAILS=you@example.com |
130 | 96 | ``` |
131 | 97 |
|
132 | | -### Watch the control-agent |
| 98 | +## Operations |
133 | 99 |
|
134 | | -The control-agent runs in the foreground terminal where you launched `start.sh`. |
| 100 | +```bash |
| 101 | +# Check security posture (24 checks + optional deep extension scan) |
| 102 | +sudo -u hornet_agent ~/hornet/bin/security-audit.sh --deep |
135 | 103 |
|
136 | | -### Watch the dev-agent / sentry-agent |
| 104 | +# Harden file permissions (runs on every boot) |
| 105 | +sudo -u hornet_agent ~/hornet/bin/harden-permissions.sh |
137 | 106 |
|
138 | | -```bash |
139 | | -sudo -u hornet_agent tmux attach -t dev-agent |
140 | | -sudo -u hornet_agent tmux attach -t sentry-agent |
141 | | -``` |
| 107 | +# Apply network firewall (run as root) |
| 108 | +sudo ~/hornet/bin/setup-firewall.sh |
142 | 109 |
|
143 | | -Detach without killing: `Ctrl+b` then `d` |
| 110 | +# Redact secrets from session logs |
| 111 | +sudo -u hornet_agent ~/hornet/bin/redact-logs.sh |
144 | 112 |
|
145 | | -### Kill everything |
| 113 | +# Monitor agent sessions |
| 114 | +sudo -u hornet_agent tmux ls |
| 115 | +sudo -u hornet_agent tmux attach -t dev-agent # Ctrl+b d to detach |
146 | 116 |
|
147 | | -```bash |
| 117 | +# Kill everything |
148 | 118 | sudo -u hornet_agent pkill -u hornet_agent |
| 119 | + |
| 120 | +# Restart |
| 121 | +sudo -u hornet_agent /home/hornet_agent/hornet/start.sh |
149 | 122 | ``` |
150 | 123 |
|
151 | | -### Restart |
| 124 | +## Tests |
152 | 125 |
|
153 | 126 | ```bash |
154 | | -sudo -u hornet_agent pkill -u hornet_agent |
155 | | -sudo -u hornet_agent /home/hornet_agent/hornet/start.sh |
| 127 | +# All 202 tests |
| 128 | +sudo -u hornet_agent bash -c "export PATH=~/opt/node-v22.14.0-linux-x64/bin:\$PATH && \ |
| 129 | + cd ~/hornet/slack-bridge && node --test security.test.mjs && \ |
| 130 | + cd ~/hornet/pi/extensions && node --test tool-guard.test.mjs && \ |
| 131 | + cd ~/hornet/bin && node --test scan-extensions.test.mjs && \ |
| 132 | + bash hornet-safe-bash.test.sh && bash redact-logs.test.sh && bash security-audit.test.sh" |
156 | 133 | ``` |
157 | 134 |
|
158 | | -## Updating |
| 135 | +## How It Works |
159 | 136 |
|
160 | | -Changes to skills, extensions, or config are tracked in this repo. After pulling: |
| 137 | +Hornet runs a **control-agent** that spawns sub-agents (dev-agent, sentry-agent) in tmux sessions and starts a Slack bridge. Messages flow: |
161 | 138 |
|
162 | | -```bash |
163 | | -# settings.json needs to be copied (not symlinked, pi writes to it) |
164 | | -sudo -u hornet_agent cp ~/hornet/pi/settings.json ~/.pi/agent/settings.json |
165 | | - |
166 | | -# Extension deps (if package.json changed) |
167 | | -sudo -u hornet_agent bash -c ' |
168 | | - export PATH=~/opt/node-v22.14.0-linux-x64/bin:$PATH |
169 | | - cd ~/hornet/pi/extensions/kernel && npm install |
170 | | - cd ~/hornet/pi/extensions/agentmail && npm install |
171 | | -' |
172 | 139 | ``` |
| 140 | +Slack → bridge (access control + content wrapping) → pi agent → tools (tool-guard + safe-bash) → workspace |
| 141 | +``` |
| 142 | + |
| 143 | +Every layer assumes the previous one failed. The bridge wraps content and rate-limits, but tool-guard blocks dangerous commands even if wrapping is bypassed. Safe-bash blocks patterns even if tool-guard is somehow evaded. The firewall blocks exfiltration even if all software layers fail. Defense in depth, all the way down. |
| 144 | + |
| 145 | +## Security Details |
| 146 | + |
| 147 | +See [SECURITY.md](SECURITY.md) for the full threat model and trust boundary diagram. |
| 148 | + |
| 149 | +## License |
173 | 150 |
|
174 | | -Skills and extensions are symlinked and update automatically. |
| 151 | +MIT |
0 commit comments