Security
Built-in Tools Security Model
Binex built-in tools run with the permissions of the orchestrator process. Two tools had critical vulnerabilities that were patched:
shell_command — Command Injection (CRITICAL, patched)
Before: Used subprocess.run(cmd, shell=True) — any agent could inject arbitrary shell commands.
After: Uses subprocess.run(shlex.split(cmd), shell=False). The command is parsed into a safe argument list. Shell metacharacters are no longer interpreted.
Mitigations:
- 30-second timeout on all shell commands
- Output truncated to 10KB
- No shell expansion (|, &&, ;, backticks have no effect)
- Executable allowlist (issue #58): even with shell=False, the tool would
still run any binary the model named (rm, curl, python -c ...). It now
runs only a conservative allowlist by default — ls, cat, head, tail,
grep, wc, echo, pwd, find, sort, uniq, cut, tr, date,
basename, dirname, stat, file, which. Anything else is blocked with a
clear message. An absolute path (/usr/bin/curl) can't bypass it — the check
is on the basename.
Widening the policy (opt-in, explicit):
- BINEX_SHELL_ALLOW="python3,git" — add specific executables to the allowlist.
- BINEX_SHELL_ALLOW_ALL=1 — disable the allowlist entirely (not recommended;
restores arbitrary command execution).
Follow-ups (tracked in #58): per-workflow tools_policy, an optional
human://approve gate showing the exact command before it runs, and sandboxed
execution (container / restricted user).
fetch_url / http_request — SSRF (patched, issue #59)
Before: Both tools fetched any URL the model produced, with redirects
enabled and no address filtering. On a server (Binex ships binex gateway and
binex scheduler), an LLM-controlled HTTP client could reach cloud metadata
endpoints (169.254.169.254), localhost admin panels, and internal services.
After: Before connecting, the URL's host is resolved and rejected if it maps
to a private, loopback, link-local, reserved, multicast, or unspecified address
(RFC 1918, 127.0.0.0/8, 169.254.0.0/16, ::1, fc00::/7, 0.0.0.0).
Redirects are followed manually and every hop is re-validated, so a public
URL can't 302 into the metadata service. Only http/https schemes are
allowed.
Opt-out: set BINEX_ALLOW_PRIVATE_URLS=1 for legitimate local requests.
Scaffolded agent server — network exposure (patched, issue #61)
Before: binex scaffold agent generated a server.py that ran
uvicorn.run(app, host="0.0.0.0", ...) — exposing the new agent to the whole
local network, with no auth, the moment it was started.
After: the generated server binds to 127.0.0.1 by default and accepts a
--host flag (mirroring binex ui). Exposing it on the network is now an
explicit --host 0.0.0.0 decision.
calculator — Arbitrary Code Execution (CRITICAL, patched)
Before: Used raw eval(expression) — any agent could execute arbitrary Python code.
After: Uses AST whitelist validation before eval:
1. Parse expression with ast.parse(expression, mode="eval")
2. Walk AST tree, verify every node is in allowed set
3. Only literals, math operators, comparisons, and whitelisted names (math functions + abs/round/min/max) are permitted
4. __builtins__ is set to empty dict
Allowed: 2 + 2, math.sqrt(16), max(1, 2, 3), 3.14 * r**2
Blocked: __import__('os').system('rm -rf /'), open('/etc/passwd').read(), any attribute access on non-math objects
Other Tools
| Tool | Risk | Mitigation |
|---|---|---|
| read_file | Path traversal | Resolved paths, no symlink following |
| write_file | Arbitrary write | Resolved paths, no symlink following |
| shell_command | Command injection | shell=False + shlex.split |
| calculator | Code execution | AST whitelist |
| http_request | SSRF | No mitigation (by design — agents need HTTP) |
Recommendations
- Run binex in a sandboxed environment when using untrusted agents
- Review workflow definitions before execution
- Monitor shell_command usage via trace logs