Documentation Index
Fetch the complete documentation index at: https://docs.agentium.in/llms.txt
Use this file to discover all available pages before exploring further.
Path & SSRF Hardening
Agents that accept paths or URLs from the LLM (which got them from a user) are a classic source of security holes:- Path traversal: the LLM helpfully passes
../../etc/passwdto yourread_filetool. - SSRF (Server-Side Request Forgery): the LLM fetches
http://localhost:9200/_searchand exfiltrates your internal Elasticsearch index. - Null byte injection:
legit.txt\0/etc/shadow— some filesystems still trim at the null. - Control character injection: ANSI escape sequences or carriage returns in paths.
safeJoin(base, rel)
What it blocks
| Attack | Example input | Behavior |
|---|---|---|
| Parent traversal | "../../etc/passwd" | throws PathSecurityError |
| Absolute path | "/etc/passwd" | throws PathSecurityError |
| Null byte | "ok\0.txt" | throws PathSecurityError |
| Control characters | "x\u0001.txt" | throws PathSecurityError |
| Prefix-matching escape | safeJoin("/etc", "passwd") from base /etcfoo | distinct directories enforced via PATH_SEP |
What it does NOT do
- Does not follow symlinks. If
users/2024.jsonis a symlink to/etc/passwd,safeJoinreturns the symlink path; reading it will still escape. Usefs.realpath()aftersafeJoinif you need symlink-aware safety. - Does not check existence. Pure path math.
- Does not normalize Unicode. Use
path.normalize()upstream if you need NFC normalization.
PathSecurityError
err instanceof PathSecurityError for fine-grained error handling.
Where it’s used by default
TheFileSystemToolkit is now hardened automatically:
../../etc/passwd) raises PathSecurityError, which the tool executor catches and surfaces to the model as a clean error string. The model can self-correct.
For tools you write yourself, route every LLM-supplied path through safeJoin:
SSRF protection — allowedHosts
URL-fetching toolkits accept an allowedHosts option that whitelists exactly which hosts the toolkit is permitted to reach.
Built-in coverage
ScraperToolkit is the canonical example; it accepts an LLM-supplied URL:
PathSecurityError("Host blocked by allowedHosts policy: ...") before any network round-trip.
Matching rules
| Allowlist entry | Matches |
|---|---|
"example.com" | example.com (exact) AND api.example.com, cdn.example.com (any sub-domain) |
"sub.example.com" | only sub.example.com and its sub-domains |
. boundary, so "example.com" does not accidentally allow notexample.com.
isHostAllowed / assertHostAllowed
Use these directly in your own URL-accepting tools:
isHostAllowed(url, undefined) and isHostAllowed(url, []) always return true (no restriction). Pass an explicit array to enforce.
Defense-in-depth recommendations
Even withsafeJoin and allowedHosts, multiple layers help:
- Run the agent as an unprivileged OS user — even if pathing escapes, the user can’t read sensitive files.
- Restrict outbound network at the firewall —
allowedHostsis a soft fence; iptables / VPC egress rules are the hard fence. - Audit
tool.resultevents — the EventBus emits every tool call; alert on suspicious patterns (many denied requests in a short window). - Use the
SandboxAgentfor any agent that runs arbitrary code or shell.
See also
SandboxAgent— full filesystem + shell isolation- Sandbox Toolkits — push code execution into E2B / Daytona
- Approval Gates — human-in-the-loop for dangerous tools