Skip to content

fix(devcontainer): spawn the devcontainer CLI outside the sandbox workspace - #227

Merged
khromov merged 1 commit into
mainfrom
fix/spawn-cwd-outside-workspace
Sep 30, 2026
Merged

khromov merged 1 commit into
mainfrom
fix/spawn-cwd-outside-workspace

Conversation

@khromov

@khromov khromov commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Bug

Creating a sandbox from any repo with a root bunfig.toml that declares a preload fails right after "Starting devcontainer…". Repro: https://github.com/khromov/gpuix-svelte (preload = ["./src/plugin.ts"]):

error: [gpuix-svelte] svelte resolved to a build without the custom-renderer API. ...
      at pin_svelte (/home/k/.codebay/instances/<id>/gpuix-svelte/src/plugin.ts:43:13)
✗ Error: devcontainer up did not return a result. See logs for details.

Root cause

devcontainerUp spawned the devcontainer CLI with cwd: workspaceDir. The CLI (devcontainer.js) has a #!/usr/bin/env node shebang, and under Bun node resolves to Bun. Bun loads bunfig.toml from the process cwd (not the script's directory), so it ran the cloned repo's preload before the CLI started.

Security: that's host-side code execution. Any repo URL a user sandboxes could run arbitrary code on the host, outside the container, with the manager's privileges — before devcontainer isolation ever applies. Here it just crashed because deps weren't installed; a malicious preload wouldn't.

Fix

  • New devcontainerCwd() (config.server.ts) returns DATA_DIR (created if missing). I picked it over os.tmpdir() because tmpdir is world-writable, so another local user could plant a bunfig.toml there.
  • devcontainerUp now spawns from devcontainerCwd(). --workspace-folder, --config and --override-config are all absolute already, so behaviour is otherwise unchanged.
  • The devcontainer --version probe (devcontainerCliAvailable) also spawns from devcontainerCwd(), so it doesn't inherit whatever the manager's cwd is. spawnCapture gained an optional cwd.

Audit of the other host spawns: every other Bun.spawn/spawnCapture runs git, gh, docker context, or the browser opener. None of them runs through Bun, and none sets a workspace cwd (git -C <workspace> changes git's directory, not the process cwd). devcontainerUp was the only spawn with a workspace cwd.

Bun has no env var that disables bunfig loading. --config/-c exists, but only when you invoke bun directly. We launch through the CLI's shebang, so we can't pass it, which is why this uses a cwd fix.

Test

devcontainer.isolated.test.ts → devcontainerUp cwd: builds a workspace whose bunfig.toml preload throws, stubs Bun.spawn to capture the cwd devcontainerUp uses, and checks that the cwd is outside the workspace. It then runs a real Bun script from that cwd and expects success. It also checks the fixture really does break a Bun process started inside the workspace. The test fails on main and passes here.

The CLI's node shebang resolves to Bun, which loads bunfig.toml from
cwd. Spawning with the cloned workspace as cwd ran the repo's preload
on the host, crashing boot and executing untrusted code.
@khromov
khromov merged commit 4cedf90 into main Sep 30, 2026
4 checks passed
khromov pushed a commit that referenced this pull request Sep 30, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.16.1](codebay-v0.16.0...codebay-v0.16.1)
(2026-09-30)


### Bug Fixes

* **devcontainer:** spawn the devcontainer CLI outside the sandbox
workspace ([#227](#227))
([4cedf90](4cedf90))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant