Skip to content

Security: Buckeyes22/pitwall

SECURITY.md

Security Policy

Supported Versions

Version Supported Notes
Unreleased alpha Security fixes are made on the default branch
Published releases No public release has been declared yet

Pitwall is pre-1.0. The API may change in backwards-incompatible ways between minor releases. When a release reaches end-of-life, its security advisories are archived but not backported.

Reporting a Vulnerability

Please do not open public GitHub issues for security vulnerabilities.

Private disclosure is preferred and expected. You can report vulnerabilities through:

  • GitHub Private Vulnerability Reporting — use the Security tab on the repository, then "Report a vulnerability". This routes directly to the maintainers without exposing the details publicly.
  • Email — no public security mailbox has been approved yet; use GitHub Private Vulnerability Reporting until one is listed here

The project targets acknowledgement within 72 hours and a substantive update within 14 days. These are best-effort targets, not an SLA.

For non-sensitive security questions or process questions, open a regular GitHub Discussion.

Scope

This policy covers the following Pitwall components and their security boundaries:

Component What is in scope
FastAPI control plane (src/pitwall/api/) Admin auth middleware, all /v1/admin/* routes including kill-switch, budget gates, and audit trails
MCP server (src/pitwall/mcp/) Admin tooling and any tool that exercises privileged operations
Kill-switch (src/pitwall/api/admin/emergency.py, src/pitwall/api/admin/kill_switch.py) POST /v1/admin/kill-switch; atomic termination and verification; optional network-revocation path
Inbound webhook HMAC (src/pitwall/webhook_receiver/, src/pitwall/webhook_dispatcher/signer.py) POST /webhooks/runpod; constant-time signature verification with bounded replay window
SSRF allow-list (src/pitwall/resolver/provider_urls.py) runpod_endpoint_id validation via ^[A-Za-z0-9][A-Za-z0-9_-]{1,63}$ at resolver/provider_urls.py::_require_endpoint_id; outbound URL construction for serverless_lb / serverless_queue / public_endpoint providers
Secrets management Central redaction for bearer/admin/webhook credentials, authorization headers, and credential-bearing URLs; AES-GCM storage for outbound webhook secrets
Pitwall Agent Routing (packages/agent-routing/) CLI/shim argument handling, local command execution, route and run-state permissions, lifecycle hooks, provider installers, bootstrap/update integrity, plugin packages, local endpoint materialization, and the loopback receiver

Known Security Model

Pitwall has two operational modes with fundamentally different trust requirements:

Single-operator, private deployment

Pitwall has one operator, one RunPod account, and one shared budget; it is not a multi-tenant authorization system. Bearer scopes limit what a credential can do but do not add tenant ownership or row-level isolation.

Production deployments must:

  1. Set PITWALL_API_TOKEN and PITWALL_ADMIN_SECRET; non-loopback API startup refuses to proceed without both.
  2. Set PITWALL_WEBHOOK_SECRET; non-loopback webhook startup refuses to proceed without it.
  3. Use scoped bearer tokens for delegated callers and reserve the all-scopes token for operators.
  4. Bind published ports to loopback or a private interface and terminate TLS at a trusted proxy.

See the full trust model and security controls in:

MCP server

The alpha MCP server is supported over local stdio only. Every network transport is rejected because HTTP authentication is not implemented. Local process access is therefore the MCP trust boundary.

Pitwall Agent Routing

Agent Routing delegates work to locally installed provider CLIs. Those children inherit the operator's filesystem, process, credential, and network authority subject to each provider's own sandbox. The default SUBAGENT_MODEL_ROUTING_UNRESTRICTED=1 profile permits unattended child execution and can bypass interactive approval prompts; set it to 0 when the selected harness can operate under its restricted policy. Treat prompts, generated patches, provider output, lifecycle hooks, route files, and workflow definitions as untrusted input.

Run records and output are private local state, but can contain source or secrets printed by a child. Prompt bodies are retained only when explicitly requested. No automatic retention period is imposed; inspect and remove records with the documented model-routing runs commands. Plugins and the source installer expose the same local execution boundary as direct shims. Optional provider installation is an explicit, confirmed mutation surface and never performs provider login.

Custom and self-hosted endpoints remain operator-supplied. API keys stay in named environment variables; route JSON stores the variable name, never the value. The optional Pitwall event receiver binds only to loopback and writes a user service only when explicitly requested; enabling that service is a separate action.

Credential roles are deliberately separate:

  • PITWALL_API_TOKEN is the broker's all-scope server credential and a legacy Agent Routing fallback.
  • PITWALL_AGENT_ROUTING_API_TOKEN is the preferred read/spend client token for route metadata and proxy traffic.
  • PITWALL_AGENT_ROUTING_SUBSCRIPTION_TOKEN is the preferred webhook:admin token used only to create a receiver subscription.
  • PITWALL_WEBHOOK_SECRET signs inbound broker webhooks and is only a legacy receiver fallback.
  • PITWALL_AGENT_ROUTING_WEBHOOK_SECRET is the preferred receiver verification secret; PITWALL_WEBHOOK_SECRET_ENV may explicitly name a different environment variable.

The detailed component threat model is maintained in packages/agent-routing/SECURITY.md, but disclosure and advisory coordination remain here under one Pitwall security home.

Security Features

Feature Implementation Default
API authorization Constant-time opaque bearer lookup; explicit read, spend, lease:mutate, webhook:admin, and server:admin scopes Required for non-loopback API; optional with warning on loopback
Admin auth server:admin bearer scope plus constant-time X-Pitwall-Secret comparison Required for non-loopback API; admin routes fail closed if absent
Inbound webhook HMAC X-Pitwall-Webhook-Signature verified by webhook_dispatcher/signer.verify; bounded timestamp window Required for non-loopback receiver; optional on loopback
SSRF allow-list runpod_endpoint_id validated by ^[A-Za-z0-9][A-Za-z0-9_-]{1,63}$ at resolver/provider_urls.py::_require_endpoint_id Always on
Kill-switch POST /v1/admin/kill-switch; ordered network deny → device revoke → compute terminate; < 30s budget; audit-logged Gated by admin auth
Fail-closed boot Refuses to start when the runtime variables required by a service are unset Always on

Out of Scope

  • Multi-tenant ownership isolation is not provided; report authorization bypasses against the documented bearer scopes, but not the absence of tenant-specific row ownership.
  • Third-party services that Pitwall calls (RunPod API, Tailscale, Redis, PostgreSQL). Report issues with those services to their respective vendors.
  • Social-engineering attacks against operators.
  • Provider-model behavior, provider subscription policies, and documented unrestricted local execution are out of scope unless Agent Routing broadens authority beyond the documented boundary or mishandles arguments, credentials, state, or installer verification.

There aren't any published security advisories