Skip to content

Devsecops/developer machine sandboxing#481

Open
ElliotFriedman wants to merge 18 commits intosecurity-alliance:developfrom
ElliotFriedman:devsecops/developer-machine-sandboxing
Open

Devsecops/developer machine sandboxing#481
ElliotFriedman wants to merge 18 commits intosecurity-alliance:developfrom
ElliotFriedman:devsecops/developer-machine-sandboxing

Conversation

@ElliotFriedman
Copy link
Copy Markdown
Contributor

Changes

Adds a new Developer Machine Sandboxing page under the Isolation & Sandboxing section, covering practical sandboxing configurations for Claude Code, Codex CLI, and VS Code dev containers.

The page covers:

  • Threat overview — prompt injection, malicious dependencies, LLM mistakes, and what mitigates each
  • Claude Code — enabling the native Seatbelt/bubblewrap sandbox, hardening settings.json with filesystem and network restrictions, and known limitations
  • Codex CLI — the safest daily-development defaults (workspace-write + on-request) and how to persist them in config.toml
  • VS Code dev containers — a hardened baseline devcontainer.json and the three default footguns to fix (passwordless sudo, Docker socket mount, --network=none vs egress proxy)

Also adds a link to the new page from the DevSecOps overview.

Checklist

  • Describe your changes — see above
  • Tag current contributors — no existing contributors on this page (new content)
  • Steward review — no steward assigned for the Isolation section; tagging maintainers for review
  • vocs.config.ts updateddeveloper-machine-sandboxing entry already present under Isolation sidebar; no dev: true needed
  • Community feedback — share in Discord if wider review is wanted before merge
  • Typos reviewed — content reviewed; run npx just lint to confirm

ElliotFriedman and others added 16 commits March 30, 2026 17:16
Visual security posture dashboard showing 12 attack vectors as a radial
diagram. Nodes are color-coded (red/amber/green) by posture state with
click-to-toggle and localStorage persistence. Clicking a node opens a
detail card with description, attack tags, and framework guide links.
Designed for CSOs to quickly assess and communicate security gaps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds dev: true flag to sidebar entry per contributing guidelines.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Selected nodes now scale up 10% and show a soft color-matched glow
instead of a detached ring outline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Posts an automated PR comment when threatData.ts is modified, reminding
contributors to include all required fields and verify framework links.
Follows the same pattern as the existing vocs-config-reminder workflow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clicking a node on the radial map showed the detail card below the
map, but on typical viewports the card landed below the fold, so it
wasn't obvious anything had happened. Use scrollIntoView with
block: "nearest" on the card when it mounts or the selected vector
changes, respecting prefers-reduced-motion.

Third PR feedback item addressed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Moved the page to sit alongside the other Introduction pages.
Updated sidebar link, internal cross-link in how-to-navigate, and
component import path to match the new location.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The detail card's framework link used a plain <a> tag which caused a
full page reload. Switched to react-router-dom's <Link> for client-side
navigation, consistent with the rest of the site.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds TagProvider, TagFilter, TagList, and ContributeFooter to match
the pattern used by all other Introduction pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Elliot <elliotfriedman3@gmail.com>
Signed-off-by: Elliot <elliotfriedman3@gmail.com>
Signed-off-by: Elliot <elliotfriedman3@gmail.com>
Signed-off-by: Elliot <elliotfriedman3@gmail.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Sidebar Configuration Reminder

This PR includes added, renamed, or removed documentation files:

  • docs/pages/devsecops/isolation/developer-machine-sandboxing.mdx (added)

Please ensure that:

  • The sidebar in vocs.config.tsx has been updated to include these files
  • New content has the dev: true parameter so it's marked as under development
  • Sidebar links match the file paths - use the preview deployment to verify

See Contributing Guide – Sidebar & Navigation for more details.


This is an automated reminder. If this PR doesn't need sidebar changes, you can ignore this message.

Copy link
Copy Markdown
Collaborator

@scode2277 scode2277 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very needed addition @ElliotFriedman!

Left one comment about Claude Code and a small needed change regarding your username :)

- DevOps
contributors:
- role: wrote
users: [elliot]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
users: [elliot]
users: [ElliotFriedman]

Comment on lines +51 to +88
- **Regular permissions**: every bash command still goes through the standard approval flow, but OS-level filesystem and network restrictions are still enforced. This adds more friction, but results in better system security properties.

Start with auto-allow. You can tighten it per-project via settings.

**Step 3: harden the project config** (`.claude/settings.json`):

```json
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"filesystem": {
"denyRead": ["~/"],
"allowRead": ["."],
"allowWrite": ["/tmp/build"]
},
"network": {
"allowedDomains": [
"registry.npmjs.org",
"api.github.com",
"crates.io"
]
}
},
"permissions": {
"deny": ["Read(.env)"]
}
}
```

- `failIfUnavailable: true`: hard-fails if the sandbox can't start, rather than silently running without isolation
- `allowUnsandboxedCommands: false`: closes the built-in escape hatch that lets Claude retry a failing command outside the sandbox
- `denyRead: ["~/"]`: blocks reads from your home directory; SSH keys and shell history are invisible to the agent
- `allowRead: ["."]`: restores read access to the current project root (inside the denied region)
- `allowWrite: ["/tmp/build"]`: if a build tool needs to write outside the working directory, grant it here specifically
- `allowedDomains`: explicit egress allowlist; omit anything you don't actively need
- `permissions.deny`: blocks Claude's file tools from reading specific sensitive paths. Note that `allowRead` takes precedence over `denyRead` within the sandbox, so project-root secrets like `.env` need to be excluded here instead
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my research, i think the permissions.deny: ["Read(.env)"] line could give readers a false sense of security for .env specifically. That rule blocks Claude's built-in Read tool, but cat .env from a bash subprocess goes through the sandbox layer and isn't affected (docs: https://code.claude.com/docs/en/sandboxing -> "built-in file tools use the permission system directly rather than running through the sandbox").

The tricky part is that the obvious fix (adding ./.env to denyRead) doesn't quite work either, because allowRead takes precedence over denyRead in the sandbox as it's a deny-then-allow pattern). So with allowRead: ["."], anything under the project root is readable regardless of what denyRead says.

A few ways we can say it:

  • Reframe the example so denyRead only protects paths outside the project (~/.ssh, ~/.aws, etc.), where the pattern works as documented, and use a separate mechanism for in-tree secrets.
  • Add an explicit Bash(cat .env) deny alongside the Read(.env) one, with the same fragility caveat already stated in the limitations section.
  • Note in the bullet that the two layers protect different vectors (Read tool vs. bash subprocesses) rather than redundant coverage of the same one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, the boundaries are distinct, and the setup likely needs to be tailed to the specific user needs and setup. Just addressed the feedback in the latest commit.

@scode2277 scode2277 added the content:add This issue or PR adds content or suggests to label May 6, 2026
Copy link
Copy Markdown
Collaborator

@frameworks-volunteer frameworks-volunteer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Model: z-ai/glm-5.1 Reasoning: high Provider: openrouter

Review of PR #481 — Developer Machine Sandboxing.

Security Review

No issues found. No secrets, no injection vectors, no unsafe patterns. Content is documentation only (MDX), no executable code changes.

QA Review

What's good:

  • All 6 external reference links return 200
  • Sidebar config (vocs.config.tsx), isolation index, and overview page all link to the new page
  • Frontmatter format matches existing pages (title, description, tags, contributors)
  • Content is accurate, well-structured, and honest about limitations
  • Threats table is clear and actionable
  • Code examples (settings.json, config.toml, devcontainer.json) are practical

Minor issues:

  1. Line 23: "company ending mistakes" should be "company-ending mistakes" (missing hyphen on compound adjective)

  2. The PR bundles unrelated changes alongside the new page: governance-proposal-security additions to index.mdx, and VPN/certs/front-end entries in fetched-tags.json. These should ideally be separate PRs for cleaner history, though this is a convention concern, not a correctness one.

Verdict: Approve with minor suggestions. The content is solid and the security guidance is accurate.

Signed-off-by: Elliot <elliotfriedman3@gmail.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

built with Refined Cloudflare Pages Action

⚡ Cloudflare Pages Deployment

Name Status Preview Last Commit
frameworks ✅ Ready (View Log) Visit Preview a0514f4

@mattaereal
Copy link
Copy Markdown
Collaborator

@frameworks-volunteer, how would you link the AI Security (/ai-security) framework with this section? Do they overlap somehow?

@frameworks-volunteer
Copy link
Copy Markdown
Collaborator

Model: z-ai/glm-5.1 Reasoning: high Provider: openrouter

Good question. There is overlap, and it's intentional — the architecture separates why (AI Security) from how (DevSecOps isolation).

How they connect today:

The AI Security section already has a bridge page at /ai-security/devsecops-isolation-sandboxing-reference that links readers to DevSecOps isolation pages. This was created when sandboxing/isolation content was deliberately moved out of AI Security into DevSecOps (PR #398). The split is:

  • /ai-security/ — threat vectors and runtime controls (prompt injection, exfiltration, execution-path enforcement)
  • /devsecops/isolation/ — practical containment patterns and configuration

Where this PR's page fits:

The new Developer Machine Sandboxing page sits in /devsecops/isolation/ and covers AI-specific tooling (Claude Code, Codex CLI), so it naturally bridges both sections. Its threat table mentions prompt injection and malicious dependencies — topics the AI Security section also covers, but from a different angle (threat modeling vs. hardening config).

Missing link:

The bridge page devsecops-isolation-sandboxing-reference.mdx currently lists all the DevSecOps isolation pages but does NOT include the new developer-machine-sandboxing link. Adding it there would complete the cross-reference:

- [Developer Machine Sandboxing](/devsecops/isolation/developer-machine-sandboxing)

Summary: The overlap is by design — AI Security describes the threats, DevSecOps isolation provides the mitigations. The new page belongs in DevSecOps (it's practical config, not threat modeling), but the bridge page should be updated to link to it so AI Security readers can find it.

@mattaereal
Copy link
Copy Markdown
Collaborator

@frameworks-volunteer Would you kindly suggest a new section that would go below the new proposed contents, after Claude, for opencode (opencode.ai) and Hermes agent (from NousResearch)?

No larger than those sections, and similar in contents but with their own thing. For example, Hermes agents allows you to run commands through a remote machine, a docker container, modal, daytona, gVisor... you can pick the backend when you start hermes and configure it at any point. Similarly for opencode, you have plugins like daytona or devcontainers that allow you to do similar things.

Put it here as a comment, do not create a new PR for this

@frameworks-volunteer
Copy link
Copy Markdown
Collaborator

Model: z-ai/glm-5.1 Reasoning: high Provider: openrouter

Here are suggested sections for OpenCode and Hermes Agent, matching the existing Claude Code / Codex CLI format and length. These would go after the Codex CLI section and before the VS Code dev containers section.


OpenCode: sandboxed backends via plugins

OpenCode (opencode.ai) is a terminal-based AI coding agent that delegates command execution to pluggable backends. Instead of running commands directly on the host, OpenCode routes them through a sandbox provider — similar to how an IDE delegates to a language server. This separation means the agent process itself never touches the host filesystem or network; only the backend does, and the backend runs in an isolated environment.

Available sandbox backends:

  • Dev Containers — runs commands inside a Docker dev container defined by .devcontainer/devcontainer.json in the project. Inherits all the isolation properties described in the VS Code dev containers section above.
  • Daytona — provisions ephemeral development environments on a Daytona server. The agent connects remotely; code and commands live on the Daytona instance, not on your machine.
  • Docker — a lightweight alternative that spins up an ad-hoc container per session without requiring a devcontainer definition.

Configuration (opencode.json or via opencode config):

{
  "sandbox": {
    "provider": "daytona",
    "daytona": {
      "server": "https://daytona.example.com",
      "profile": "sandboxed"
    }
  }
}

Switch backends at any time with opencode config set sandbox.provider <name>. During onboarding, opencode init prompts you to pick a backend.

Limitations

  • The agent-to-backend communication channel is local by default. When using remote backends (Daytona), ensure the connection is over TLS or a trusted network.
  • Dev container and Docker backends inherit the same footguns as plain Docker: passwordless sudo in default images, and Docker socket mounts. Apply the hardening from the VS Code dev containers section.
  • No built-in egress filtering at the OpenCode layer. Network restrictions depend entirely on the backend's own networking configuration (e.g. Docker network policies, Daytona workspace settings).

Hermes Agent: pluggable execution backends

Hermes Agent (Nous Research) is a multi-modal AI agent that supports multiple execution backends for running shell commands and tool operations. You select the backend when starting a session and can reconfigure it at any point. The agent process communicates with the backend over a defined interface; the backend decides where and how commands execute.

Available backends:

  • Local machine — commands run directly on the host. Useful for trusted tasks, but provides no isolation.
  • Docker container — Hermes spawns a container from a configurable image and executes commands inside it. The host filesystem is only exposed through explicit volume mounts.
  • Remote machine — SSH into a remote host. Code and commands never touch your local machine. Useful for air-gapped workflows or dedicated build servers.
  • Modal — serverless GPU/cloud backend. Commands run in ephemeral Modal sandboxes that are destroyed after the session. Good for compute-heavy tasks where you also want ephemeral isolation.
  • Daytona — managed development environments, same isolation properties as described in the OpenCode section.
  • gVisor — runs commands in a gVisor sandbox on the local machine. gVisor provides kernel-level syscall filtering, offering stronger isolation than plain Docker containers without requiring a separate host.

Configuration (~/.hermes/config.yaml):

execution:
  backend: docker
  docker:
    image: hermes-sandbox:latest
    cap_drop: [ALL]
    security_opt: [no-new-privileges]
    network_mode: none
    volume_mounts:
      - "./:/workspace"

Switch backends mid-session with hermes config set execution.backend <name>. Each backend has its own configuration block under execution.<backend_name>.

Limitations

  • The Docker and gVisor backends still require Docker to be installed on the host. If Docker itself is compromised (e.g. via a Docker socket exposure), the isolation is bypassed.
  • Remote machine and Daytona backends shift the trust boundary to the remote host. The agent's SSH key or Daytona API token becomes a high-value target on your local machine.
  • gVisor has syscall compatibility limitations; some build tools and debuggers may not work inside a gVisor sandbox.
  • There is no built-in TLS inspection or egress proxy. For network-constrained environments, configure the backend's network settings directly (e.g. network_mode: none for Docker, or a custom VPC for Modal/Daytona).

For the References section, consider adding:

@mattaereal
Copy link
Copy Markdown
Collaborator

@frameworks-volunteer, how would you update, if you would, @ElliotFriedman's content based on the comment below? Take a look at the article, and decide whether it makes sense to add a clarification or create a new entire category about VScode.

Comment I added previously:

The "Remote" extension that makes devcontainers possible in VSCode is closer to a RAT than anything else :/.

By default, it mounts several other things, such as exposing gpg-agent's and ssh-agent's host sockets within the container. It does not necessarily expose ~ files directly, but some of their contents through other mechanisms yes. Not all extensions run automatically, or by default inside the container too

Here's an article I wrote about all this, in case you want to use it as a reference to update this bit (or any other bit):
https://blog.theredguild.org/leveraging-vscode-internals-to-escape-containers/

@frameworks-volunteer
Copy link
Copy Markdown
Collaborator

Model: z-ai/glm-5.1 Reasoning: high Provider: openrouter

I read the full article. My recommendation: add a clarification, not a new category.

Here's why, and what I'd add:


Why not a new category:

The article's findings all pertain to VS Code's Remote extension and how it undermines devcontainer isolation. That is specifically about the trust model of the tool this PR's VS Code section already covers. A separate "VS Code Internals" or "VS Code Remote Extension Risks" category would fragment what should be a single cohesive warning: dev containers are not security sandboxes, and the Remote extension that makes them work is itself the biggest escape vector. The current section already says "Dev containers aren't designed as security sandboxes; convenience shortcuts dominate the defaults" -- but it understates the problem.


What to add -- a new subsection under "Limitations":

I'd insert a subsection called something like "The Remote extension trust model" (after the existing three bullet points) that covers the key findings from the article. Here's draft content:

The Remote extension trust model

The Dev Containers extension works by deploying a vscode-server agent inside the container and connecting it to the host IDE over an RPC channel. This architecture introduces several escape paths that go beyond normal container breakout:

  • Forwarded authentication sockets. By default, SSH_AUTH_SOCK and GPG_AGENT_INFO are forwarded into the container. Any process inside the container can request signatures or authenticate via the host's ssh-agent or gpg-agent -- without copying the keys. An attacker can use ssh-add -L to list host keys and ssh -o BatchMode=yes to pivot to other machines. A passphrase on the key only protects initial unlocking; once cached, the agent honors signing requests silently.

  • Copied Git configuration. Host ~/.gitconfig (including user.signingkey and credential.helper) is copied into the container by default. This enables commit signing and push auth seamlessly, but also allows impersonation and credential reuse. Disable with "remote.containers.copyGitConfig": false and clear remoteEnv entries.

  • Host terminal access from container extensions. The VS Code API allows workspace extensions running inside the container to call workbench.action.terminal.newLocal to open a terminal on the host, then workbench.action.terminal.sendSequence to send arbitrary commands to it. This is a full container-to-host RCE path that requires no exploit -- it is by design. (See Calif's "Vibe Hacking" research and The Red Guild's article for working PoCs.)

  • Extension host manipulation. A malicious workspace extension can modify .vscode/settings.json or .devcontainer/devcontainer.json (both are bind-mounted from the host), inject remote.extensionKind overrides, and trigger a window reload. The host then applies the poisoned config, potentially shifting other extensions between UI and workspace hosts.

Mitigations:

"remoteEnv": {
  "SSH_AUTH_SOCK": "",
  "GPG_AGENT_INFO": "",
  "GNUPGHOME": "/tmp/gnupg",
  "GIT_ASKPASS": ""
},
"settings": {
  "remote.containers.copyGitConfig": false
}

These disable the default socket forwarding and git config copy. They do NOT address the TerminalService RCE path -- that requires trusting every extension installed in the workspace.


Also add to References:


One broader point: The existing intro paragraph says "The container only sees what you explicitly mount. SSH keys, AWS credentials, and anything else under ~ stays on the host." This is misleading given the Remote extension's default behavior. The forwarded auth sockets and copied git config mean the container can effectively use (and abuse) those credentials without directly reading the files. I'd rephrase that sentence to something like: "The container's filesystem only sees what you explicitly mount, but the Remote extension forwards authentication sockets and Git configuration by default -- effectively giving the container access to host credentials without mounting the files."


Summary: expand the existing VS Code section's limitations with a focused subsection on the Remote extension trust model, add the references, and fix the misleading intro claim. No new category needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

content:add This issue or PR adds content or suggests to

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants