root. You can instead declare an unprivileged user in your image, so processes, terminals and filesystem operations run as that user while the sandbox API keeps the privileges it needs for drive mounts, networking and keep-alive.
Why the sandbox API stays root
The sandbox API is PID 1 in the sandbox. It mounts Agent Drive, configures egress networking, installs the CA bundle and manages standby, and all of those require root. This is why a plainUSER directive is not enough on its own: in a plain container it de-privileges the sandbox API itself, which breaks everything mentioned above. On Blaxel, the runtime does not apply the image USER to the sandbox API. It starts the API as root and passes your user down to it, and the API drops privileges for the operations it runs on your behalf, keeping root only for the infrastructure work listed below.
This scopes privileges inside the sandbox. It is a defense-in-depth measure: the microVM boundary remains the isolation guarantee between your sandbox and everything else.
Declare a user in your image
Create the user in your Dockerfile, declare it withUSER, and turn the feature on with BL_SANDBOX_USER_ENABLED:
USER syntax: app, 10001, app:app or 10001:10001. The user must exist in the image, and it cannot resolve to uid 0. Make sure your workload owns every directory it writes to.
Pass the user explicitly
If you need root-only preparation at boot, such as achown or a mkdir outside the user’s home, use an entrypoint that runs as root and hands over to the sandbox API with the --user flag:
USER out of that Dockerfile so the entrypoint itself runs as root, and point ENTRYPOINT at the script. The --user flag is the explicit opt-in, so it does not need BL_SANDBOX_USER_ENABLED. Setting BL_SANDBOX_USER in your image environment is equivalent to USER, and still requires the enable variable.
What runs as your user vs. stays root
Calls to the sandbox API from inside a sandbox process keep the same identity. There is no parameter or environment variable that asks for root, so a process cannot use the API to escalate its own privileges. To refuse those calls altogether, isolate the sandbox API.
Isolate the sandbox API
Calls to the sandbox API through Blaxel require credentials. Calls from inside the sandbox tolocalhost:8080 do not. Set BL_SANDBOX_API_ISOLATION to refuse connections from your workload to the sandbox API, so code running in the sandbox cannot use it to run commands, read files or open terminals:
BL_SANDBOX_API_ISOLATION also runs your workload as the image USER, without BL_SANDBOX_USER_ENABLED.
At boot, before your workload starts, the sandbox API installs firewall rules on its port. Refused connections get a TCP reset. The sandbox does not start when the rules cannot be installed.
Only the sandbox API port is filtered. Preview URLs and your application ports are not affected.
To check it, open a terminal in the sandbox and run the following commands. The image needs
curl.
id -un prints your image user, and curl fails with Connection refused. The same call through Blaxel with your credentials still succeeds.
Without a USER directive, or with USER root, the sandbox API installs the rules, logs a warning and runs your workload as root.
Limitations
- Access granted only through a supplementary group of your user is not honored on filesystem API calls, which apply the primary group.
- Files that already exist in the image and belong to root stay read-only for your workload. Change their ownership at build time or in a root entrypoint.
- With neither
BL_SANDBOX_USER_ENABLEDnorBL_SANDBOX_API_ISOLATIONset, the sandbox runs everything as root.
Build a sandbox image
Create reusable sandbox images with Dockerfiles.
Variables and secrets
Pass configuration and secrets to a sandbox.