Skip to main content
r5d.chat runs AI-generated code on your infrastructure. This page describes what the security model guarantees, and equally importantly what it does not.

Trust boundaries

Browser sessions are cookie-based and signed. Private browser API handlers check the session and resource ownership or project membership; public health, published snapshots and token-authorized flows have separate policies. The browser never receives a workspace token, and browser workspace and artifact traffic is mediated by the control plane.
Each workspace has a random 32-byte bearer identity stored in a Kubernetes Secret and mounted into the pod. It maps to one user and authenticates the legacy artifact/conversation callback and daemon protocols. It is not sent to the browser, but must not be treated as secret from root processes in that user’s workspace. Automation machine APIs use separate scoped credentials. The active ARTIFACT_SCOPE is derived by the control plane and injected only into the child shell process for that conversation, never pod-wide; it is a caller-supplied scope, not a signed per-conversation capability.
r5dchat artifacts presents the workspace identity plus x-artifact-scope. The server resolves that scope and independently checks current project membership or standalone-chat ownership on every list, read, upload, overwrite, and delete. Knowing or substituting an identifier is not an authorization grant. A workspace credential can select another scope already authorized to that user; this is not isolation between that user’s chats.
Tenant pods receive no service-account token, host path, runtime socket, or host namespace. automountServiceAccountToken is false and service links are disabled, so a workspace has no ambient Kubernetes credential to use.
Provider keys, custom headers, MCP headers, and OIDC client secrets are AES-256-GCM encrypted with SETTINGS_ENCRYPTION_KEY and stay in the control plane.
Provider, MCP, and OIDC destinations pass a guard that rejects non-HTTPS URLs, credential-bearing URLs, private/loopback/link-local/metadata addresses, and unsafe redirects, unless explicitly relaxed.

MCP Apps isolation

Interactive MCP Apps render untrusted server-provided HTML in sandboxed frames, using per-server origins on a dedicated registrable domain. A sibling subdomain of the product domain is not sufficient. Route these origins only to the separate sandbox listener, never the authenticated product Service. The chart’s sandbox has no service-account token and, with NetworkPolicy enabled, no egress. It receives SETTINGS_ENCRYPTION_KEY for signed payloads, so it is not a secret-free process. Browser content restrictions and pod network policy are separate boundaries. See MCP Apps for deployment requirements and verification before enabling it.

Workspace pod hardening

Workspace containers run as root on purpose, so agents can install packages for their task. Root is constrained:
Root in an unprivileged container is not a complete sandbox against hostile code. A container escape through a kernel vulnerability remains possible. For mutually untrusted tenants, use a VM boundary such as Kata or gVisor, Pod Security admission, resource quotas, image policy, monitoring, and dedicated node pools.
The five allowed capabilities support container-local APT/dpkg operations: SETUID/SETGID let APT use its _apt download sandbox, and CHOWN/DAC_OVERRIDE/FOWNER let the package manager maintain files owned by package users. Dropping them all breaks installation even with UID 0. These capabilities also let workspace code change users and ownership inside its container; they are not a per-command grant or an isolation boundary between that user’s processes. No SYS_ADMIN, SYS_PTRACE, NET_ADMIN, NET_RAW, or MKNOD is granted. Packages needing unavailable kernel/device/service privileges are not supported; do not enable privileged mode to install them. Use apt-get directly, without sudo. The home volume persists, but packages installed outside /home/r5d do not survive container replacement. See Workspace lifecycle for checks and safe rollout behavior. Enable a VM boundary with:

Workspace network boundary

With networkPolicy.enabled: true and a NetworkPolicy-enforcing CNI, the chart permits workspace traffic to:
  • This release’s control-plane pods on TCP 3000 in the release namespace. Artifact, conversation CLI and automation callbacks require this exception. WORKSPACE_CONTROL_PLANE_URL normally uses the internal Service’s service.port (default 80), which forwards to the container’s TCP 3000. The destination selector includes both chart name and release instance; it is not a namespace-wide allow rule. The reciprocal control-plane ingress rule permits same-namespace pods labelled app.kubernetes.io/managed-by: r5d-chat on TCP 3000, even when public ingress is restricted to tunnel or ingress-controller pods.
  • DNS on UDP/TCP 53. networkPolicy.workspaceDnsTo selects the peers. Empty community defaults allow any destination on these ports; managed reference values restrict them to CoreDNS. This is not a DNS-name or DNS-content filter.
  • Public IPv4 when networkPolicy.workspaceInternetEgress: true. The 0.0.0.0/0 rule excludes workspaceInternetExcept: community defaults exclude RFC1918, loopback and link-local ranges; managed reference values additionally exclude CGNAT and the cluster’s public node addresses. Review the actual values for your cluster. There is no equivalent public IPv6 allow rule.
Turning internet egress off leaves DNS and control-plane callbacks enabled; this is not an air gap. Custom callback URLs need explicitly reviewed matching policy. NetworkPolicies are additive: another policy selecting these pods may allow more traffic. Rendered policy is a contract, not proof of live CNI configuration, Service/NAT behavior, or protection when policy is disabled.

Reachability is not authorization

The callback exception is a destination/port boundary, not a URL-path allowlist. All routes on that listener are network-reachable; /api/health intentionally returns {"ok":true} without authentication. That response alone is neither a network-policy bypass nor unauthorized data access. Sensitive handlers must still validate the appropriate browser session, workspace identity and scope, or automation run capability. Source pod labels and access to the internal Service do not authenticate an HTTP caller. Test allowed callbacks separately from denied destinations and route authorization. A negative network test must use a disposable, secret-free HTTP canary outside the callback/DNS/public-IP allow rules, with the exact target and request approved by the operator before the run. Do not substitute metadata, Kubernetes, database, other tenants, or production services. Missing approval or an unhealthy canary is an unrun/inconclusive test, not a pass. A path-limited callback requirement would need a separate authenticated callback listener or gateway, a complete method/path allowlist, and tests showing that workspaces cannot bypass it through the product Service, pod IPs or public origin. It must also preserve artifact/CLI/automation functionality with internet egress disabled. The current chart does not implement or promise that boundary; do not disable callbacks or widen namespace trust to approximate it.

File and artifact boundaries

There are two deliberately different boundaries:
  • Agent tools intentionally operate anywhere inside the container. The agent’s boundary is the pod itself, because installing and configuring software requires writing outside the home directory. The private workspace is not exposed through a user-facing file browser.
  • Shared artifacts are remote control-plane resources. They are never mounted at /home/r5d, and an arbitrary private file is not published until the agent explicitly runs r5dchat artifacts push. Artifact paths reject traversal, backslashes, control characters, empty segments, and overlong input. Storage keys are opaque and unrelated to paths shown to collaborators.
The control-plane artifact PVC mounts whole at a dedicated directory with an fsGroup; workspace home PVCs never mount it. This separation prevents a workspace process from bypassing artifact authorization with filesystem access.

Threats to plan for

Content the agent reads, whether a web page, a document, or an MCP tool description, can contain instructions aimed at the model. Combining broad web access with high-privilege MCP tools increases the blast radius. Give MCP servers narrowly scoped credentials.
Tool definitions are model instructions. r5d.chat fingerprints them on approval and surfaces later drift, but the initial trust decision is yours. See MCP servers.
Agents can run expensive commands. Workspace CPU and memory limits bound a single pod; namespace quotas bound the aggregate. Set both.
A workspace with internet egress can send private files or artifacts it is authorized to pull anywhere. Set networkPolicy.workspaceInternetEgress: false for sensitive tenants, accepting that agents can then no longer install packages from the internet. DNS and control-plane callbacks still work; this setting is not a complete exfiltration barrier. Scope authorization limits which shared artifacts are available but cannot constrain what an authorized model does with bytes after reading them.
Before setup is claimed, anyone who reaches the URL can become the administrator. Always set SETUP_CLAIM_TOKEN before exposing an unclaimed installation.
Provider API keys are write-only, but custom headers are returned to the authenticated owner so they remain editable. Treat header values as user-visible secrets.

Hardening checklist

1

Set a claim token before exposure

SETUP_CLAIM_TOKEN in the Secret, claimed immediately after go-live.
2

Keep the outbound guard strict

Leave ALLOW_PRIVATE_EGRESS and ALLOW_INSECURE_HTTP at false unless a specific endpoint requires otherwise.
3

Use a VM runtime for untrusted tenants

workspace.runtimeClassName: kata or gvisor.
4

Keep NetworkPolicy enabled

networkPolicy.enabled: true, and decide deliberately about workspaceInternetEgress.
5

Apply namespace quotas

Bound total pods, CPU, memory, and storage so one tenant cannot starve the rest.
6

Use TLS end to end

Terminate HTTPS at the ingress and set publicUrl to the https:// URL.
7

Protect the recovery set

Store SETTINGS_ENCRYPTION_KEY in a secrets manager and back it up with the database and artifact PVC at one recovery point. Keep artifact storage inaccessible to workspace pods.
8

Keep a local admin account

Even with SSO enabled, as an identity-provider outage recovery path.
9

Update images regularly

The workspace image carries a large package surface; rebuild it to pick up security updates.

Multi-tenancy guidance

Colleagues under one policy. Default settings are appropriate: standard container isolation, NetworkPolicy on, internet egress enabled.

Reporting a vulnerability

Report security issues privately through the repository’s security advisory process rather than a public issue.