Isolation and secrets
What runs where, what is wiped when a runtime stops, who can see your data, and how to hand a kernel an API key without ever pasting it into a notebook. This page describes the mechanisms; the security page and the privacy policy cover the commitments.
One machine per runtime
Every runtime is a dedicated, single-tenant virtual machine, provisioned fresh for that session on the provider, GPU and size you picked, and terminated when the session ends. The instance and its boot volume are never reused for another session or another user: the hypervisor is the isolation boundary, and no two kernels ever share a machine.
Inside the machine, your notebook kernel, the web terminal and SSH logins all
run as the same unprivileged user (user, uid 1000), never as root, and start
in /home/user/workspace.
No inbound ports
The machine accepts no inbound connection on the data path. The kernel, the
terminal and sshd bind to localhost only, and the runtime opens one
outbound encrypted tunnel to the platform's session gateway at boot;
every byte between your browser (or your ssh client) and the kernel travels
through that tunnel. Nothing on the VM listens on a public address. The only
inbound the platform reserves for itself is the provisioning channel,
restricted to the control plane's own source addresses.
The other direction is deliberately narrow too. A runtime cannot reach
another runtime, the platform's database or cache, or control-plane
internals. Its outbound access is the public internet, subject to the
Environment's egress policy (open, blocked, or an allowlist of CIDRs), and
the platform endpoint it needs to run.
A runtime holds no standing cloud credential either. The instance identity is the minimum the bootstrap needs (with IMDSv2 required); the credential that mounts your workspace is short-lived, scoped to exactly that workspace, and fetched at mount time rather than baked into any image. The kernel gateway's own authentication token is minted on the machine and never leaves it; the browser holds only a single-use, 60-second WebSocket ticket.
Each session also receives a session API key with a scope strictly narrower than a personal key: it can stream experiment metrics and fetch the session's own secrets, but cannot manage secrets, open SSH, or act as you elsewhere. It is revoked within a minute of the session stopping.
What survives a stop, and what does not
Stopping a runtime terminates the machine. The only durable thing attached to
it is the workspace filesystem mounted at /home/user/workspace
(~/workspace).
| Location | After stop |
|---|---|
~/workspace (files, notebooks, datasets, checkpoints) | Kept. Your workspace filesystem, shared by every runtime of the workspace. |
~/workspace/.ns-cache (pip cache, Hugging Face cache, per-Environment pip installs) | Kept. Platform-managed, hidden from the Files page; see Packages. |
The rest of /home/user (~/.cache, ~/.local, ~/.vscode-server, ~/.config, git credentials) | Wiped. |
/tmp, /scratch (local NVMe) | Wiped. Scratch is the fast local disk for temporary data. |
Changes to the image (sudo pip, apt-get, edits under /opt, /etc, /usr) | Wiped. Put them in the Environment to keep them. |
| The VM, its boot volume, and every secret value it was handed | Destroyed. |
Data at rest on the platform side is encrypted with platform-managed keys: the workspace filesystem's object store, the database, and the secrets store.
Who can see your data
Access is enforced by the API on every request, keyed to the identity in your session token or API key, never to anything in a request body.
- Workspace members see the workspace's notebooks, files, environments, experiment runs and runtimes, according to their role. Viewers read; editors and owners change things. Membership is the only way to write into a workspace.
- Share grants give one named person view and fork/copy access to a single file, notebook, run or environment without adding them to the workspace. Every recipient read is brokered by the API: no storage credential, mount or filesystem path is ever issued to the recipient, a shared file never appears on their runtime, and a copy lands in their workspace under their quota, never touching the source. Revoking a grant makes the next read indistinguishable from "never shared".
- Public links for files, notebooks and runs resolve an unguessable token to a read-only view. They are revocable, can carry an expiry, are rate-limited per IP, and attribute only the sharer's display name, never an email or account id.
- Shared environments are redacted for anyone but the owner: the recipe shape is visible, environment-variable values are blanked, and build error text is withheld. A recipient who edits gets a fork with a fresh id; the original is never modified.
- Someone who is not a member and holds no grant gets the same "not found" answer as for an object that does not exist, so a URL leaks nothing about what it points at.
Secrets: the place for an API key
A Hugging Face token, an OpenAI key, a private index credential. The wrong places for it are an environment spec (it would be shared, forked, and rendered into a build), a notebook cell (it would be saved, shared, and committed), and the image (it would be pulled by every runtime). The right place is Workspace Secrets: Settings → Secrets, once secrets are enabled for your deployment.
- A secret is a name (
^[A-Z][A-Z0-9_]{0,63}$) and a value, at workspace scope. The value is written to the platform's managed secrets store and never comes back: no API response, log line, database column or process argument ever carries it, and replacing a value never reveals the old one. Listing shows names and a non-secret hint. - Managing secrets is human-only and membership-gated: creating, replacing and deleting need an editor or owner signed in through the browser. A kernel's session key cannot enumerate or change the store.
- An Environment references secrets by name (
runtime_secret_names, andbuild_secret_namesfor builds). Names are ordinary, non-secret handles: they are visible to share recipients, copied verbatim on fork, and never rendered into the Dockerfile. This is what makes a shared environment safe to launch: the names resolve against the launching workspace's store, never the author's. - At launch, the runtime is handed only a pointer. After boot, the machine
fetches the values itself over the tunnel, authenticated by its own session
key, and writes them to a
0600file on its ephemeral disk that the kernel and terminal source in-process. Values reachos.environ;psshows only static command text; nothing rides the provisioning payload or a log. - A referenced name that does not exist in your workspace never fails the
launch: the session starts without it, the notebook nudges you toward
Settings → Secrets, and
NS_USER_SECRETS_MISSINGlists what was missing.
In a cell:
import os
import neural_studio as ns
token = ns.secrets.get("HF_TOKEN") # a clear error if the name is not referenced or not defined
os.environ["HF_TOKEN"] # the same value; every referenced secret is an env var
Build-time secrets (a private pip index, a git token for a
post_install step) follow the same by-name pattern and reach the build only
as BuildKit secret mounts on the pip install and post-install steps:
tmpfs inside that one RUN, never an image layer, never an ENV, never
command text. A missing build secret fails the build, deliberately the
opposite of the runtime path.
The share-time secret scanner
Mistakes happen, so every sharing surface scans what it is about to expose.
Before an environment is shared or made more visible, before a file or
notebook grant is created, and before a public link is minted, the content
is checked for credential-shaped strings: cloud key ids, sk--style API
keys, GitHub, Slack, Hugging Face and Google tokens, private-key headers,
webhook URLs, user:credential@ URLs, and an entropy heuristic for
secret-looking environment variables.
If it finds something, the share is refused with the findings listed, and you can either remove the secret or confirm and proceed. A finding shows at most the first four characters of the match, never the value. Environment saves report the same findings as advisory warnings. The scanner is best-effort: it is a safety net, not a guarantee, and it never blocks an operation by failing.