Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,16 @@ This reduces the blast radius of a compromised worker by keeping plaintext API k
- Avoid logging request headers and environment variables in production environments.
- Assume agent output is untrusted input; validate and sanitize before using it in other systems.

## Kubernetes worker process identity

The **Kubernetes instancer** (`instancer/backends/k8s.py`) schedules worker `Job` pods using the published worker image. That image is currently built to run its entrypoint as **root** (default for the base image), so the pod spec does not set `runAsNonRoot` / `runAsUser` yet.

**Why this matters:** uploaded project code runs inside the worker; running the process as non-root limits impact if the container boundary is reached.

**Mitigations operators can use today:** isolate namespaces, restrict service accounts, use network policies, prefer **proxy-token mode** for API keys (see above), and keep worker images updated.

**Hardening path:** add a non-root `USER` in the worker image (with correct ownership of `WORKSPACE_BASE` / agent dirs), then set pod or container `securityContext` (`runAsNonRoot`, `runAsUser`, `fsGroup` as needed). Until that image change lands, expecting `securityContext` alone would break startup.

If your deployment **does not use** the Kubernetes instancer (for example only Docker-based workers), this section does not apply to that path.


64 changes: 0 additions & 64 deletions backend/.env.production

This file was deleted.

5 changes: 2 additions & 3 deletions backend/api/mcp/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
import hmac
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from asgiref.typing import ASGIApplication, ASGIReceiveCallable, ASGISendCallable, Scope

# Header name for MCP API key (ASGI headers are lowercase bytes).
MCP_API_KEY_HEADER = b'mcp-api-key'

if TYPE_CHECKING:
from asgiref.typing import ASGIApplication, ASGIReceiveCallable, ASGISendCallable, Scope


class McpApiKeyMiddleware:
"""ASGI middleware that rejects requests without a valid MCP-API-Key header."""
Expand Down
10 changes: 3 additions & 7 deletions backend/instancer/backends/k8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,9 @@ async def start_worker(self, options: StartWorkerOptions) -> StartWorkerResult:
),
spec=client.V1PodSpec(
automount_service_account_token=False,
security_context=client.V1SecurityContext(
# TODO(trixter-osec): consider in the future hardening and running as non-root?
# run_as_user=65534,
# run_as_group=65534,
# run_as_non_root=True,
# fs_group=65534, # not supported by the python client apparently...?
),
# Pod runs as root until the worker image supports a non-root USER; see SECURITY.md
# ("Kubernetes worker process identity"). Enable runAsNonRoot/runAsUser when the image does.
security_context=client.V1SecurityContext(),
restart_policy='Never',
containers=[
client.V1Container(
Expand Down
4 changes: 2 additions & 2 deletions deploy/gce-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# Prerequisites:
# - gcloud CLI authenticated with a project set
# - A domain with DNS you can point to the VM IP
# - backend/.env filled in from .env.production template
# - backend/.env copied from .env.example and filled with production secrets
set -euo pipefail

# ── Defaults ──
Expand Down Expand Up @@ -98,7 +98,7 @@ echo ""
echo "3) On the VM, clone and deploy:"
echo " git clone <YOUR_REPO_URL> /opt/evmbench"
echo " cd /opt/evmbench/backend"
echo " cp .env.production .env # then edit with real secrets"
echo " cp .env.example .env # then edit with real secrets"
echo ""
echo " # Generate secrets easily:"
echo " python3 -c \"import secrets; print(secrets.token_urlsafe(32))\""
Expand Down
Loading