Classification: Critical
Applies to: All contributors and AI agents operating this system
| Threat | Risk | Mitigation |
|---|---|---|
| AI hallucination destroys files | Critical | HITL + Docker sandbox + read-only mounts |
| Prompt injection escapes container | Critical | Directory boundary checking + localhost-only |
| Malicious shell command execution | Critical | Command classification + approval workflow |
| Data exfiltration | High | Network bind to 127.0.0.1 only |
| Path traversal | High | resolve_safe_path() validation |
The backend must run inside a Docker container. It never executes directly on the host OS.
# docker-compose.yml
services:
backend:
build:
context: .
dockerfile: backend/Dockerfile
ports:
- "127.0.0.1:8000:8000" # Never 0.0.0.0
volumes:
- ./:/app/workspace:rw # Working directory
- ./raw_sources:/app/workspace/raw_sources:ro # Read-onlyAll file paths are validated before use.
from backend.src.security import resolve_safe_path
safe_path = resolve_safe_path("../../../etc/passwd")
# Raises: ValueError("Path traversal blocked...")Rules:
- Paths are resolved to absolute form
- Symlinks are followed and validated
- The resolved path must be inside
WORKING_DIR /raw_sourcesis mounted read-only
User-facing directories are explicitly whitelisted for visibility and write access.
USER_ROOTS (user-facing, read/write):
USER_ROOTS = {"raw_sources", "workspace", "wiki", "skills"}raw_sources/— Source code for graph analysis (agent can read)workspace/— Working outputs, drafts, reports (agent can read/write)wiki/— Markdown knowledge base (agent can read/write)skills/— Skill definitions (agent can read/write for discovery + stubs)
SYSTEM_ROOTS (hidden, system-internal):
SYSTEM_ROOTS = {"node_modules", "venv", ".git", ".vscode", ".link", ...}- Hidden directories starting with
.are blocked unless explicit exception (e.g.,.env) - Agent writes to
wiki/andworkspace/freely; blocks to.git,.venv, etc. - Graphify and Bootstrap operations respect this boundary automatically
Mutating commands require explicit user approval via the Web UI.
Auto-blocked commands:
rm,mv,cp(with overwrite)pip install,npm installdocker,sudo- Any command with
>,>>, or|redirection
Auto-allowed commands:
ls,cat,grep,find,head,tailpwd,echo,git status
Flow:
User sends command
→ Backend classifies command
→ If mutating: create HITL request
→ Frontend shows approval modal
→ User clicks Approve/Reject
→ If approved: execute command
→ Result returned to chat
Backend binds exclusively to 127.0.0.1.
# main.py
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"], # Never *
)This prevents external access even if the host firewall is misconfigured.
Tools are classified by risk to determine Human-in-the-Loop (HITL) approval requirements.
TIER_0_RO (Read-only, no approval needed):
read_file,search_files,list_directoryweb_search,read_url(information gathering only)read_todo,read_conversation- Bypass HITL: Yes
- Reasoning: No local state mutation; external I/O is idempotent
TIER_1_WRITE (Safe write operations, no approval):
create_directory,write_file(non-destructive)add_todo_task,mark_todo_done,update_identity- Bypass HITL: Yes
- Reasoning: Write to user-visible paths (wiki, workspace, todo); user can undo
TIER_2_EXTERNAL (External with side effects, requires approval):
run_workflow,run_agentic_workflow(delegates to external agents)- Bypass HITL: No (currently unused, reserved for future)
- Reasoning: Unpredictable impact from sub-agents
TIER_3_DESTRUCTIVE (Destructive, requires approval):
delete_file,copy_file(with overwrite)- Shell commands with
rm,mv, redirects, pipe ops - Bypass HITL: No
- Reasoning: Irreversible state change on user files
Classification in backend/src/tools.py:
def get_tool_tier(name: str, args: dict) -> OperationTier:
ro_tools = {
"read_file", ...,
"web_search", "read_url", # ← No HITL
}
if name in ro_tools:
return OperationTier.TIER_0_RO
if name in ("write_file", "create_directory", ...):
return OperationTier.TIER_1_WRITE
# ... TIER_2 and TIER_3 logic- Never commit
.envfiles to git (see.gitignore) - Keys are injected at runtime via environment variables
- No API keys exist in source code
Before submitting code:
- Does this change expose any new endpoints?
- Are new file operations using
resolve_safe_path()? - Are new shell commands classified as mutating/readonly?
- Is the CORS origin restricted to localhost?
- Are secrets injected via env vars, not hardcoded?
- Does
docker-compose.ymlbind to127.0.0.1?
If you discover a security vulnerability, please report it immediately. Do not open a public issue.