Files
ServerKit/SECURITY.md
T
Juan DenisandClaude Fable 5 751dde7a7d fix(deploy): threaded gunicorn worker — gevent-websocket class broke WebSocket
The app runs flask-socketio with async_mode='threading' (the backend
is real-thread based: jobs scheduler, queue bus, agent registry), where
engineio serves WebSocket via simple-websocket on the raw socket. The
systemd unit template and Dockerfile still launched gunicorn with the
GeventWebSocketWorker, which ALSO answers the upgrade — the client got
HTTP/1.1 101 twice and read the second one as a frame ('Invalid frame
header'), so every panel silently degraded to polling. Proven by
hexdump (double 101, first 'frame' byte 0x48 'H') and fixed live:
single 101 + 0x81 text frame, socket.io connects through Cloudflare.

- unit template + Dockerfile: gunicorn -w 1 --threads 100 (single
  PROCESS stays mandatory — in-memory agent gateway)
- requirements: pin simple-websocket explicitly (was transitive-only)
- CLAUDE.md / ARCHITECTURE.md / SECURITY.md single-worker notes updated

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 00:14:49 -04:00

2.8 KiB

Security Policy

Supported Versions

ServerKit is under active development. Security fixes are applied to the latest release line and the main branch.

Version Supported
1.6.x ✅
< 1.6 ❌ (please upgrade)

The agent is versioned independently (agent-vX.Y.Z); always run a recent agent build, as several Windows service and credential-handling fixes landed in the 1.6.x line.

Reporting a Vulnerability

Please report security issues privately — do not open a public issue for anything exploitable.

Please include affected version(s), reproduction steps, and impact. Coordinated disclosure is appreciated — give us a reasonable window to ship a fix before any public write-up.

Agent Trust Model

The multi-server agent is powerful by design — operators should understand its trust boundaries:

  • agent.key is a host-equivalent secret. Agent API credentials are stored AES-256-GCM encrypted under a key derived from host-stable identifiers (hostname + machine ID on Linux, hostname + computer name on Windows). Because that key is derived only from values available on the host itself, the encryption is at-rest tamper-resistance / off-host-exfil protection (e.g. a leaked backup) — not confidentiality against a local root/SYSTEM user, who can re-derive the key. Anyone who can read this file on the host can recover the credentials. The 0600 file permissions are the real access control; protect it like a root/SYSTEM secret.
  • Remote command execution is gated. Arbitrary command execution (system:exec) and interactive PTY sessions are controlled by the agent's Features.Exec flag, which is off by default. Enable it only on servers where you intend the panel to run shell commands.
  • Transport & connection controls. Agents authenticate to the panel with per-connection HMAC-SHA256 (with nonce/replay protection and a timestamp-skew check), and the panel enforces a per-server IP allowlist. Use wss:// (TLS-terminated) in production.
  • SERVERKIT_INSECURE_TLS=true disables certificate verification for all agent connections. It is intended for local development/testing only — never set it in production.

For a detailed internal audit of the panel, see SECURITY_AUDIT.md.

Deployment Note

The agent gateway keeps all connected-agent state in-memory in a single process. Run the panel with a single gunicorn worker process (threaded worker, -w 1 --threads N — not the gevent-websocket worker class); multi-worker deployments can misroute agent commands. See docs/ARCHITECTURE.md.