Agent? Fetch sharkmagic.si/docs/llms.txt or this page as markdown
Security#
What Shark does today and how to report a vulnerability.
Short version: every command runs in its own Firecracker microVM with its own Linux kernel; third-party API tokens stay outside the VM by default; each Space has an outbound network policy.
What we do#
Compute isolation#
- A microVM per command. Each command gets a fresh Firecracker microVM with its own kernel, restored from a snapshot and destroyed when the command ends. No process, memory or kernel state survives into the next command; only the Space's committed files do. Services (Postgres, Redis) and kept jobs run in VMs of their own.
- Every API command is in a VM. The node runs strict mode: an API command never runs on the host.
- Per-account snapshot templates. The memory template a VM is restored from is a separate physical copy per account, so two accounts never share template pages (this closes a cache side channel between accounts). Memory deduplication across accounts (KSM) is off. Verified locally (P108 L1: 0 shared physical pages across accounts);
- Node protection. The node agent and system run in a reserved cgroup slice; all accounts' VMs run in a capped
slice, with per-account quotas (Spaces, disk, concurrent commands) and admission control that refuses new work with
503 out_of_capacityinstead of overcommitting memory.
Secrets#
- Never in the VM by default. A secret stored with
expose: inject(the default) reaches a command only as a placeholder (shk_ph_…, different per command). The node's egress proxy, outside the VM, swaps in the real value only in requests to the hosts you scoped it to, and scrubs it from responses. An agent that can run code in the Space can use the token against its intended API, but cannot print or send the value elsewhere. expose: execis an explicit, per-secret opt-in that puts the value in the environment of the commands that ask for it; the API warnssecret_exposed_to_codewhen you choose it.- Values are sealed per Space at rest (AES-256-GCM), never returned by any API, never written to the Space's files, never replicated, and redacted from logs. Forks do not copy secrets.
- Verified locally (P111 N1–N4, 2026-11-05): 0 occurrences of a secret value in the guest's environment, memory, files, outputs, logs or registration messages over 696 authenticated requests; fail-closed in 6/6 broken setups.
Network#
- Per-Space egress policy by API:
allowlist(the hosted default, with a base list of package registries and GitHub),denyor, where allowed,open. Web traffic is matched by name; bare IPs need an explicit publiccidr:port; private and link-local ranges (including cloud metadata addresses) are always denied, and so are the node's own addresses except on the ports it serves to the internet (443 and 80), even when a policy entry names them. - In the hosted configuration a VM has no network card: its TCP and DNS reach only the node's egress proxy, which enforces the policy and performs secret injection.
- Verified locally (P111 E1/E2): 24/24 policy probes as expected, private destinations denied in every mode.
Accounts, keys, API#
- The account comes from the credential, never from the request body. Another account's Space answers
404, never403, so ids cannot be probed; Space ids carry 128 random bits. - API keys are shown once and stored only as an HMAC under a server-side pepper; compared in constant time; scoped
(
exec,files:write,secrets:write, …). Failed authentications are rate-limited per address. - HTTPS only; the node refuses plain HTTP except on loopback. Behind its TLS proxy, only that proxy may set the client address.
- Preview URLs (live on the hosted node) are private by default: a one-time, 60-second login link sets a
__Host-cookie (Secure, HttpOnly, SameSite=Lax) for that one preview host; the cookie never reaches your server process. Local gates: 30/30 unauthorized attempts refused with 0 requests reaching the server (P112 H2.1). On the hosted node (P130 flow, 2026-11-07): requests without the cookie, a reused link and an expired link were all refused (401), turning public off refused again, and removing the port revoked it (404).
Where the agent harness runs#
Only the commands an agent runs go to microVMs. In the hosted products the harness itself (the agent program and its
file tools) runs in the Space's session VM (shark code) or on your own machine (the SDK), never on a shared node.
Our density tests also use a third mode, self-hosted only: the harness on the host with its shell routed through
Shark's shim. In that mode only the shell goes to a VM; the harness's own file tools (read, write, edit) act on the
host with whatever access the harness's user has. We found this in our own test run on 2026-11-05 (P113 r2-8: agents
running as root read files outside their project), so the test now runs the harness as a dedicated unprivileged user
that cannot read anything outside its Space, checked before each run. If you run a harness this way on your own
machine, give it the same kind of user; it is not a mode we offer.
Privacy of usage data#
Usage records hold counts and durations only, never command text, paths or file contents. Operators can turn off the logging of command text per account on the host.
Reporting a vulnerability#
Write to <SECURITY_CONTACT>. Please include steps to reproduce and the request_id of any API response involved.
Test only against Spaces of your own account.
Your side#
- Keep API keys in the environment or
~/.shark/credentials(0600); never in prompts, repos or the Space. - Give agents keys with only the scopes they need; keep
secrets:writeandnetwork:writefor yourself. - Store third-party tokens as
injectsecrets with a narrowscope.hosts; useexeconly for values code must read. - Start Spaces with
egressset to the narrowest allowlist that works. checkpointbefore you rely on a result surviving a server failure.
