Security
Hoard implements multiple security layers to protect your data while enabling AI agent access.
Security Layers
┌─────────────────────────────────────────┐│ MCP Request │└─────────────────┬───────────────────────┘ │ ▼┌─────────────────────────────────────────┐│ 1. Token Authentication ││ • Verify Bearer token present ││ • Token must exist in config │└─────────────────┬───────────────────────┘ │ ▼┌─────────────────────────────────────────┐│ 2. Scope Checking ││ • Token has required scope ││ • Tool matches allowed scopes │└─────────────────┬───────────────────────┘ │ ▼┌─────────────────────────────────────────┐│ 3. Rate Limiting ││ • Per-token limits ││ • Per-tool limits ││ • Byte/chunk caps │└─────────────────┬───────────────────────┘ │ ▼┌─────────────────────────────────────────┐│ 4. Sensitivity Filtering ││ • Check entity sensitivity ││ • Require 'sensitive' scope │└─────────────────┬───────────────────────┘ │ ▼┌─────────────────────────────────────────┐│ 5. Audit Logging ││ • Log all tool calls ││ • Track access patterns │└─────────────────────────────────────────┘Token Scopes
Tokens define what actions are permitted:
security: tokens: - name: "claude-code" scopes: ["search", "get", "memory.read"] - name: "admin" scopes: ["search", "get", "memory", "sensitive", "sync", "ingest"]| Scope | Allows |
|---|---|
search | search() tool |
data.search | Alias for search |
get | get(), get_chunk() |
data.get | Alias for get |
memory | Memory read and write (legacy scope) |
memory.read | memory_get, memory_search |
memory.write | memory_put and other memory write tools |
ingest | inbox_put |
sync | sync, sync_status, sync_run, embeddings_build |
agent.register | Register agents (Orchestrator) |
agent.self | Manage own agent state (Orchestrator) |
agent.read | List agents (Orchestrator) |
task.create | Create tasks (Orchestrator) |
task.claim | Poll and claim tasks (Orchestrator) |
task.execute | Start/complete/fail tasks (Orchestrator) |
task.manage | Cancel tasks (Orchestrator) |
task.read | Read task details (Orchestrator) |
artifact.read | Read artifacts (Orchestrator) |
artifact.write | Write artifacts (Orchestrator) |
event.read | Poll events (Orchestrator) |
event.write | Publish events (Orchestrator) |
cost.read | Cost summary and budgets (Orchestrator) |
cost.write | Cost reporting (Orchestrator) |
workflow.create | Create workflows (Orchestrator) |
workflow.manage | Start/pause/resume/cancel workflows (Orchestrator) |
workflow.read | Read workflow status and definitions (Orchestrator) |
sensitive | Access entities with sensitivity='sensitive' or 'secret' |
Orchestrator Tokens
HOARD_SERVER_SECRETis required to start the write-enabled server and can act as an admin token.HOARD_REGISTRATION_TOKENis required foragent.registerwhen onboarding new agents.
Rate Limiting
Prevents runaway agents from exhausting resources:
rate_limits: search_requests_per_minute: 30 get_requests_per_minute: 60 chunks_returned_per_hour: 5000 bytes_returned_per_hour: 50000000 # 50MBPer-Tool Limits
| Tool | Rate Limit Key | Default |
|---|---|---|
search | search_requests_per_minute | 30/min |
get | get_requests_per_minute | 60/min |
get_chunk | get_requests_per_minute | 60/min |
memory_get | get_requests_per_minute | 60/min |
memory_put | get_requests_per_minute | 60/min |
memory_search | get_requests_per_minute | 60/min |
sync | get_requests_per_minute | 60/min |
sync_status | get_requests_per_minute | 60/min |
sync_run | get_requests_per_minute | 60/min |
inbox_put | get_requests_per_minute | 60/min |
embeddings_build | get_requests_per_minute | 60/min |
Byte/Chunk Caps
Hourly caps prevent bulk exfiltration:
- 5,000 chunks/hour — Limits enumeration
- 50MB/hour — Limits large document scraping
Sensitivity Levels
Entities can have sensitivity levels:
| Level | MCP Access | Set By |
|---|---|---|
normal | All tokens with get scope | Connectors, CLI |
sensitive | Only tokens with sensitive scope | Connectors, CLI |
secret | Only tokens with sensitive scope | Connectors, CLI |
Setting Sensitivity
Set sensitivity via connectors when indexing:
EntityInput( source="my_source", source_id="id", sensitivity="sensitive", ...)Anti-Exfiltration Measures
Hoard prevents bulk data extraction:
| Protection | How It Works |
|---|---|
No export_all | Tool doesn’t exist |
No list_all | Can’t enumerate entities |
| Rate limits | Caps requests over time |
| Byte caps | Limits total data returned |
| Audit logs | Detects suspicious patterns |
Audit Logging
All MCP requests are logged to the SQLite database (audit_logs table). Each log entry includes:
- Token name
- Tool called
- Success/failure status
- Chunks and bytes returned
- Timestamp
View audit logs by querying the database:
sqlite3 ~/.hoard/hoard.db "SELECT * FROM audit_logs ORDER BY request_at DESC LIMIT 10"Connector Security (v1)
| Aspect | v1 Reality |
|---|---|
| Permissions in manifest | Informational only, not enforced |
| Network access | Connectors can make any request |
| File access | Connectors can read any file |
| Execution | Same process as Hoard core |
Mitigations:
- Connectors reviewed before recommendation
- Provenance tracking shows which connector indexed what
- Users install connectors explicitly
Future: v2 will add OS-level sandboxing.
Token Management
Create Token
hoard tokens add my-token --scopes search,get,memory.read,ingestList Tokens
hoard tokens listRemove Token
hoard tokens remove my-tokenBest Practices
- Minimal scopes — Only grant what’s needed
- Separate tokens — One per AI tool
- Review audit logs — Check for anomalies
- Keep Hoard updated — Security fixes ship regularly
Configuration
Full security configuration:
security: tokens: - name: "claude-code" token: "hoard_sk_..." scopes: ["search", "get", "memory.read"] - name: "admin" token: "hoard_sk_..." scopes: ["search", "get", "memory", "sensitive", "sync", "ingest"]
rate_limits: search_requests_per_minute: 30 get_requests_per_minute: 60 chunks_returned_per_hour: 5000 bytes_returned_per_hour: 50000000Next Steps
- MCP Interface — How tools use security
- Configuration — All security options
- MCP Tools — Tool scope requirements