cloudflare / cloudflare/sandbox-sdk

Support `user` flag for sessions

Open
#678 2 comments 1 reaction 0 assignees View on GitHub
Dominant language
TypeScript
Stars
1.1k
Forks
114
Avg merge
22h 42m
Merged PRs (30d)
14

Description

There's no clean way to run a session's commands as a non-root user today.

- The container's control plane runs as root (legitimately — it appends the CF runtime CA cert to the system bundle, manages FUSE mounts, etc.).
- `Bun.spawn` for the persistent bash shell inherits root.
- Every `session.exec()` framing script runs as root.

User code that wants to run unprivileged (e.g. Claude Code's `--permission-mode bypassPermissions` refuses under root) has no good options:

- `exec runuser -u claude bash` as the first scripted command **hangs**: `exec` replaces bash before the framing script writes its exit-code file, so `session.exec()` polls forever.
- `runuser -u claude bash` (no `exec`) spawns a child shell, blocking the parent root bash until the child exits — same hang.
- Per-command `runuser -u -- bash -lc ` wrappers work but pollute every call site and lose the persistent shell state across commands (cwd, env, functions defined in earlier commands).

This is related to #677.

## Proposal

Add `user?: string` to `SessionOptions`. When set, the container resolves it to a uid/gid at session boot and spawns the persistent bash shell under that user via `Bun.spawn`'s `uid`/`gid` options. Control plane stays root;
only the session shell drops privileges.

```ts
const session = await sandbox.createSession({ user: 'claude' });
await session.exec('whoami'); // → 'claude'
```

Persistent shell state still works because privilege drop happens once at spawn, not per command.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.