Strands Shell Security Model
Strands Shell exists to answer one question: what should this agent be allowed to touch? The answer is enforced by the Kernel, a single mediation boundary that every filesystem, network, and credential operation flows through. This page explains where that boundary sits, what it guarantees, and the threat models it does and doesn’t cover.
The framing that matters most: Strands Shell is a mediation layer, not a hardened sandbox. It enforces what an agent should reach through deny-by-default policy. It runs in the same process as your code, not in a VM. Getting this distinction right is the difference between an appropriate deployment and a false sense of safety.
The Kernel boundary
Section titled “The Kernel boundary”All effects flow through the Kernel. There’s no path around it: the shell makes no fork, no exec, and no raw syscalls, because the engine runs entirely in userspace. A command that wants to read a file, reach a URL, or use a credential asks the Kernel, and the Kernel applies policy.
The default Kernel is backed by an in-memory virtual filesystem and enforces four guarantees:
- Filesystem isolation. The VFS exposes only explicitly bound paths. No path can escape its declared mounts, and
..components, symlinks, and bind-path tricks are checked against the mount boundary. - Network SSRF guard. A two-layer check filters network access: a URL-level parse plus IP filtering at DNS-resolution time. It blocks RFC1918, link-local, loopback, IMDS, IPv4-mapped IPv6, 6to4, and Teredo addresses by default.
- Credential injection. Secrets are matched per URL prefix with a path-boundary check and injected only on the original request, then stripped on redirects.
- No syscalls. There’s no
fork,exec, or raw syscall path for a command to reach the host environment.
A custom Kernel (for embedding the shell in another runtime) carries its own security properties. The guarantees above describe the bundled implementation.
Deny by default
Section titled “Deny by default”Out of the box a shell is empty: no files, no network, no credentials. You add capability explicitly. The TOML config defaults bind mode to copy (the safe choice), but the Python and Node.js constructors default to direct; always pass mode explicitly in code. The principle is least privilege, and the practices that follow from it:
- Prefer
copyoverdirectbinds for source code. Acopybind snapshots files into the VFS, isolating the agent from your live filesystem. Reservedirectfor output directories where the agent must persist results. - Scope binds narrowly. Bind
/my/project/src, not/my/projector/. The agent doesn’t need your.git, your.env, or yournode_modules. - Allowlist URLs explicitly. Don’t allowlist a bare
https://; that disables the SSRF guard. List the specific endpoints the agent needs. - Keep a timeout set. The config-driven API defaults to a 30-second per-command timeout, which bounds runaway commands. Raise it for long-running work rather than removing it.
- Set
max_output. Cap the output an agent can generate so a single command can’t fill memory. 1 MiB is a reasonable default.
The configuration guide shows how to apply each of these.
How credentials stay out of reach
Section titled “How credentials stay out of reach”The credential design solves a specific problem: an agent that can make HTTP requests should be able to use a secret without being able to read it. A secret in an environment variable fails this, because any command can print the environment.
Strands Shell injects credentials at request time, keyed to a URL prefix. The value doesn’t enter the agent’s reach: it’s absent from the environment, from command output, from error messages, and from the Lua scripting context. The Kernel injects only on the original request and doesn’t re-inject on a redirect, even one that points back to the same host. That closes the exfiltration path where an agent follows a crafted redirect to a logging endpoint and reads the forwarded header.
What is out of scope
Section titled “What is out of scope”Some properties are explicitly not part of the security boundary. Treating them as guarantees would be a mistake:
- Resource exhaustion within configured limits. Limits are best-effort. They catch runaway agents; they don’t stop deliberate attempts to exhaust CPU or memory. Use OS-level cgroups for hard caps.
- Speculative execution and side channels. The same-process architecture doesn’t defend against timing attacks. Use VM isolation for that threat model.
- Multi-tenancy within one process. A shell instance is single-owner. Sharing one instance across mutually distrusting agents is a documented non-goal.
- Memory-safety exploits in the engine itself. The Kernel mediates policy; it’s not a defense against an attacker who compromises the host process.
- Reading files the agent was granted. A bind is a grant. An agent reading a directory you bound is the system working as designed.
Choosing the right isolation
Section titled “Choosing the right isolation”Match the tool to the threat model:
- “My agent shouldn’t touch anything I haven’t allowed.” The Kernel handles this directly. This covers the common cases: a coding agent on a repository, a research agent with a scoped API key, a CI assistant. No container required.
- “An untrusted tenant is running arbitrary adversarial code.” Add OS-level isolation. Run each shell instance inside a container or microVM, and let the Kernel handle in-process mediation on top. Construction is cheap, so one shell per session is the intended pattern.
The two layers compose. The Kernel gives you fine-grained, fast, deny-by-default mediation; the container gives you a hard kernel boundary. For adversarial workloads, use both.
Reporting a security issue
Section titled “Reporting a security issue”A bypass of filesystem mediation, the SSRF guard, or credential injection is a security issue, not a normal bug. Reaching a path outside a bound mount, defeating the metadata-service block, exfiltrating an injected credential, or causing one MCP session to read another session’s state all qualify.
Don’t open a public GitHub issue. Report through the AWS Vulnerability Disclosure Program on HackerOne or by email to aws-security@amazon.com. The repository’s SECURITY.md has the full policy and the complete in-scope and out-of-scope lists.