Full Security Audit
Background tasks, network egress, scheduled jobs, and prompt-injection history. Audit only — nothing was changed.
Executive Summary
No suspicious background tasks, no unknown outbound connections, no evidence of prompt injection. Two credential files are world-readable and one injection defense gap exists.
Background Processes & Launch Agents
Every running process and launch agent was enumerated and attributed. All are expected infrastructure.
| Process | PID | What it is | Verdict |
|---|---|---|---|
| hermes gateway (default) | 615 | Main Telegram gateway, venv python | ✅ Expected |
| hermes gateway (aigov) | 610 | AIGov profile gateway | ✅ Expected |
| hermes gateway (opencode25jul) | 618 | OpenCode profile gateway | ✅ Expected |
| gbrain serve ×2 | 3461/3465 | Knowledge-graph MCP servers (bun) | ✅ Expected |
| mcp_stdio_watchdog ×2 | 3460/3464 | MCP supervision scripts | ✅ Expected |
| ollama serve | 616 | Local model server, binds 127.0.0.1 only | ✅ Expected |
| Telegram / Finder / Activity Monitor | — | User apps | ✅ Expected |
| All other processes | — | Apple system daemons (opendirectoryd, WindowServer, etc.) | ✅ Expected |
Launch agents: only 3 Hermes gateway plists, Google Updater (standard), and Ollama. No system LaunchDaemons, no /etc/cron.d, no user crontab, no screen/tmux sessions, no SSH authorized keys, no unknown binaries.
Network & Outbound Connections
Every live connection was captured and attributed. Nothing connects anywhere unexpected.
| Endpoint | Owner | Used by | Verdict |
|---|---|---|---|
| 91.108.56.199:443 | Telegram (MTProto) | Telegram desktop app | ✅ Expected |
| 149.154.166.110:443 | Telegram (MTProto) | Hermes gateway (bot polling) | ✅ Expected |
| 34.36.133.15:443 | ollama.com (Google Cloud) | Hermes gateways — model API | ✅ Expected |
| 2001:67c:4e8:f004::9:443 | Model provider IPv6 endpoint | Hermes gateways only | ✅ Expected |
| api.aiand.com:443 | Cloudflare-fronted (Qwen3.6 provider) | Hermes gateways — custom provider | ✅ Expected |
Listening ports: only rapportd (macOS system service, *:49161) and ollama (127.0.0.1:11434 — localhost only). Firewall: enabled. No webhook listeners. No SSH server exposure.
MCP servers: gbrain + gbrain-knqx — both local binaries, no remote endpoints, no keys in MCP env. ✅
Scheduled Tasks (Cron)
19 Hermes cron jobs exist; only 4 are enabled. All deliver to origin (this chat) or local. No exfiltration patterns in any script.
| Enabled job | Schedule | Deliver | Verdict |
|---|---|---|---|
| Macro Watch — AI Bubble | 09:00 daily | origin | ✅ Benign |
| gbrain nightly dream cycle | 02:00 daily | origin | ✅ Benign |
| SG AI Pulse Weekly | Sun 09:00 | origin | ✅ Benign |
| Zeus Index Daily Auto-Sync | 06:00 daily | origin | ✅ Benign |
Script review (zeus-digest.py, pipeline_runner.py, zeus-index-daily-sync.sh): no curl/wget/nc/scp/rsync/base64/eval patterns — nothing that could ship data out. 15 disabled jobs are dormant. No system crontab exists.
Prompt Injection — History & Defenses
Checked logs, the session database, and the defense wiring. No evidence of a successful injection. One defense gap found.
History check: grepped all logs for injection markers (0 hits) and scanned the session DB for classic injection phrases ("ignore previous instructions", "you are now", "jailbreak", "DAN mode"). The 40 keyword matches were all [CONTEXT COMPACTION — REFERENCE ONLY] handoff summaries and legitimate study content — not injection attempts. No session shows a role-hijack or tool-abuse pattern.
Defenses active: Tirith (installed at ~/.hermes/bin/tirith, enabled, fail-closed) ✅ · context-file scan in prompt_builder.py ✅ · strict scan on memory writes ✅ · tool results wrapped in <untrusted_tool_result> tags ✅ · approvals manual + cron deny ✅ · allow_private_urls false ✅.
sanitize_web_results() patch in tools/web_tools.py is not present (0 matches). Web search/extract results flow raw into context — the one layer where a hostile page could attempt injection. The patch exists in the web-injection-hardening skill and takes ~10 minutes to apply.Credentials & File Permissions
Two OAuth credential files are world-readable (644). Everything else is correctly locked down.
| File | Perms | Risk | Fix |
|---|---|---|---|
| google_token.json | 644 ⚠️ | 🔴 Live OAuth access + refresh tokens readable by any local user | chmod 600 |
| google_client_secret.json | 644 ⚠️ | 🔴 OAuth client secret readable by any local user | chmod 600 |
| state.db | 644 ⚠️ | 🟠 Full conversation history readable by any local user | chmod 600 |
| config.yaml.bak | 644 ⚠️ | 🟡 Config backup (may contain the provider key) | chmod 600 |
| kanban.db / SOUL.md / hermes_state.db | 644 ⚠️ | 🟡 Data + persona files world-readable | chmod 600 |
| .env | 600 ✅ | All API keys — correctly locked | — |
| .env.cfoat-broken backup | 600 ✅ | Backup copy — correctly locked | — |
Config keys: one provider API key (Qwen3.6, 67 chars) is stored in config.yaml instead of .env — 🟠 High. It should live only in HERMES_QWEN36_API_KEY in .env (which already exists). Git: .env never committed; history shows only security-hardening commits. ✅
Config Posture — Hardening Opportunities
Medium-severity items. None are active leaks; all reduce attack surface.
| Setting | Current | Recommendation |
|---|---|---|
| redact_pii | false | 🟡 Enable — redacts personal data in tool output |
| allowed_chats | empty | 🟡 Restrict to known chat IDs — bot currently accepts any chat from allowed users |
| allow_lazy_installs | true | 🟡 Set false — blocks auto-installs of packages mid-task |
| website_blocklist | empty | 🟡 Add known-hostile domains |
| approvals.mode | manual ✅ | Only destructive commands prompt; consider smart for LLM risk assessment |
| cron_mode | deny ✅ | Cron cannot run destructive commands |
| tirith | enabled + installed ✅ | Fail-closed injection guard |
| allow_private_urls | false ✅ | SSRF protection on |
Prioritized Fix List
All fixes are local, fast, and non-destructive. Nothing here requires a rebuild or restart of services.
| # | Finding | Severity | Effort | Fix |
|---|---|---|---|---|
| 1 | google_token.json + google_client_secret.json world-readable | 🔴 | 1 min | chmod 600 ~/.hermes/google_*.json |
| 2 | state.db + config.yaml.bak + kanban.db + SOUL.md world-readable | 🟠 | 1 min | chmod 600 ~/.hermes/state.db ~/.hermes/config.yaml.bak* ~/.hermes/kanban.db* ~/.hermes/SOUL.md |
| 3 | web_tools.py injection sanitizer missing | 🟠 | 10 min | Apply web-injection-hardening skill patches |
| 4 | Qwen3.6 API key in config.yaml | 🟠 | 2 min | Remove from config; keep only in .env |
| 5 | redact_pii off, allowed_chats empty, lazy installs on, blocklist empty | 🟡 | 5 min | hermes config set per item |