| Entity | Trust Level | Rationale |
|---|---|---|
| HTTP caller (with valid token) | Trusted | Bearer token authenticates the caller |
| HTTP caller (no token) | Untrusted | Only /health is accessible |
| Agent (Claude SDK) | Sandboxed | Runs with controlled tool set, no direct secret access |
| MCP Server subprocess | Internal | Shares SQLite, scoped by conversation ownership |
| External cron trigger | Trusted | Must provide Bearer token for /task/check |
All endpoints except /health require a Bearer token:
Authorization: Bearer <API_TOKEN>API_TOKENis set via environment variable at deployment time.- Missing or invalid tokens receive
401 Unauthorized. - If
API_TOKENis not configured, the server returns500to prevent open access.
The agent never sees deployment secrets:
ANTHROPIC_BASE_URLis passed to the SDK as an environment variable. While not a secret, it should be injected at deployment time alongsideANTHROPIC_API_KEYfor consistency.ANTHROPIC_API_KEYandCLAUDE_CODE_OAUTH_TOKENare unset from the Bash environment in thepreToolUsehook before any shell command executes.API_TOKENis only used by the Express middleware; the agent cannot read it.- Secrets and configuration must be injected via environment variables or cloud secret managers — never baked into the Docker image.
PicoClaw operates within well-defined mounted volumes:
| Path | Purpose | Access |
|---|---|---|
/data/org |
Org persona, org skills, managed MCP config | Read-only (optional, via ORG_DIR) |
/data/memory |
User persona (CLAUDE.md), agent workspace, .claude/ SDK session state |
Read/Write |
/data/store |
Persistent SQLite (conversations, messages, tasks); sync target from /tmp |
Read/Write |
/tmp |
Runtime SQLite (messages.db); fast local I/O, synced to /data/store after each response |
Read/Write (ephemeral) |
The agent has full Bash access within the container, but the container itself limits the blast radius.
The MCP server enforces ownership rules:
- Main session (
PICOCLAW_IS_MAIN=1): Can list and manage all tasks across conversations. (LegacyNANOCLAW_IS_MAINis accepted as fallback.) - Non-main sessions: Can only manage tasks belonging to their
conversation_id. send_messagewrites are scoped to the current conversation.
- Foreign key constraints are enforced (
PRAGMA foreign_keys = ON). - WAL mode prevents corruption from concurrent reads during sync.
- Database sync uses
wal_checkpoint(TRUNCATE)before file copy to ensure consistency.
- Place PicoClaw behind an API Gateway or reverse proxy (AWS API Gateway, ALB, Nginx).
- Use TLS termination at the gateway level.
- Restrict direct access to the container port.
- Use cloud secret managers (AWS Secrets Manager, Alibaba Cloud KMS) for
ANTHROPIC_BASE_URL,ANTHROPIC_API_KEY, andAPI_TOKEN. - Rotate
API_TOKENperiodically. - Never commit
.envto version control.
- Monitor
status=timeoutandstatus=errorrates. - Alert on unexpected
401patterns (potential brute force). - Track
/task/check remainingto detect task backlog.
- Run as non-root user (
node, uid 1000) — already configured in Dockerfile. - Use read-only root filesystem where possible.
- Set memory and CPU limits at the cloud platform level.
| Area | Rating | Details |
|---|---|---|
| Authentication | Good | Bearer token; unauthenticated access limited to /health (version info only) |
| Secret isolation | Good | PreToolUse hook scrubs ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, API_TOKEN from Bash environment |
| File isolation | Acceptable | Agent can access all files within the container (by design); volume mount boundaries limit scope |
| Database security | Acceptable | No encryption at rest; relies on volume permission controls |
| Injection protection | Good | Zod schema validation on MCP tool inputs; XML escaping on message output |
| Log security | Good | Structured pino logging; full request bodies are not logged |
| Concurrency safety | Good | Per-conversation mutex lock prevents concurrent agent execution on same conversation; different conversations run in parallel; conflict returns 409 |
- Single-instance SQLite: SQLite does not support multi-writer concurrency across instances. Cloud platform concurrency controls should limit to one active instance per conversation scope.
- No request-level rate limiting: Rate limiting should be implemented at the API Gateway layer.
- Agent Bash access: The agent can execute arbitrary commands within the container. This is by design (Claude Code requires it), but the container boundary limits impact.