# Isolation model

The container that runs Claude holds no tokens and no credentials, and it cannot reach GitLab, Slack, SharePoint, or any other service directly. When a project connects a service, that service gets its own worker container, and only the worker mounts its credentials, read-only. Claude reasons and writes code, but a credential never passes through it. See [Credentials](/docs/security/credentials/) for the details.

## No tokens, no shortcuts

Every container Speedwave renders, the Claude container, the hub, and each worker, gets the same hardening: every Linux capability dropped, privilege escalation blocked, a read-only root filesystem, and `/tmp` mounted so nothing written there can execute. A CPU and memory cap is a resource limit, not a security boundary: it stops a runaway process, nothing more.

Claude never talks to a service directly. It talks to the hub, the hub forwards to the right worker, and only that worker holds the credential the call needs: a compromised worker exposes one service, [a compromised hub exposes nothing](/docs/under-the-hood/tool-gateway/). [The office worker, which converts Word, Excel, PowerPoint, and PDF files, goes further](/docs/under-the-hood/workers/): no credentials, no route to the gateway, so even a compromised document parser cannot reach the internet.

```mermaid
flowchart LR
  Claude["Claude container<br/>(no tokens)"] -->|HTTP| Hub["Hub<br/>(zero tokens)"]
  Hub -->|HTTP| Slack["Slack worker"]
  Hub -->|HTTP| GH["GitHub worker"]
  Slack -->|"reads"| ST[("Slack credentials, read-only")]
  GH -->|"reads"| GT[("GitHub credentials, read-only")]
```

## It can't build your Gradle or .NET project

The Claude container ships only node with npm and python3 with pip, plus git and a shell. It has no route to your host toolchain: no JDK, no Gradle, no Go, no .NET, no host container engine. Speedwave built a worker for whitelisted host build commands, then removed it: letting Claude trigger host execution weakened the isolation this container exists to provide.

## Links you click are checked too

The chat UI never navigates in-app when you click a link Claude wrote. It hands the URL to `open_url`, which opens it in your default browser instead, after rejecting URLs over 8192 characters and checking SSRF rules: only `http`/`https`, no loopback, private, or link-local addresses. A manipulated link can't reach a service on your network. The same validation protects plugin OAuth URLs; see [Writing a plugin](/docs/plugins/writing-a-plugin/) for that case.

## Projects don't share a network

Isolation applies per project too. Each project gets its own container network and tokens directory, so a worker in one project cannot reach another project's network or credentials, and logging in to a service for one project doesn't authenticate it for another. See [Container topology](/docs/under-the-hood/container-topology/) for what each project creates.

This sits on two more layers: individually hardened containers, and a lightweight VM (Lima on macOS, WSL2 on Windows) separating all of them from the host at the kernel level. An attacker who compromised Claude would land in an empty-handed container with the VM still between them and your machine. See [How it works](/docs/understand/how-it-works/) for the picture.