sharkmagic.docs
Security

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_capacity instead 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: exec is an explicit, per-secret opt-in that puts the value in the environment of the commands that ask for it; the API warns secret_exposed_to_code when 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), deny or, where allowed, open. Web traffic is matched by name; bare IPs need an explicit public cidr: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, never 403, 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:write and network:write for yourself.
  • Store third-party tokens as inject secrets with a narrow scope.hosts; use exec only for values code must read.
  • Start Spaces with egress set to the narrowest allowlist that works.
  • checkpoint before you rely on a result surviving a server failure.