Security policy
Security Policy
cubby-network is an open-source NetOps control plane that, in production, holds credentials for real network devices and can change live network state. Vulnerability reports are taken seriously.
Reporting a vulnerability
Do not open a public GitHub issue for a security report. Instead:
- Email the maintainers with
[cubby-network security]in the subject line. - Include reproduction steps, the version / commit you tested, and the impact you believe the issue has.
- We will acknowledge within 72 hours and aim to provide a remediation plan within 14 days for critical issues, 30 days for high severity.
When in doubt, report it. We would much rather see a non-issue than miss a real one.
Supported versions
Until the project reaches v1.0.0 we patch only the main branch. Once we cut a stable release, we will support the latest minor for security fixes.
Threat model summary
The harness is designed against the following classes of attack:
- Identity spoofing on the API. All routes require a validated bearer token. Request bodies cannot override
requested_by/actor_roles— seeapps/api/security.stamp_principal. - Tamper of audit evidence. Bundles are signed (HMAC-SHA256 by default, Ed25519 in production) and chained via
prev_sha256. Verify withapps/cli/verify_evidence.py. - Unauthorised / spoofed change approvals. Every medium- or high-risk change requires a quorum of cryptographically signed
SignedApprovalenvelopes evaluated against aChangeAdvisoryBoardchain. Signatures bind the approver to the canonical plan hash (canonical_plan_payload), so swapping the plan after sign-off fails verification. Approvals use a signer distinct from evidence — see the custody section below. - Credential leakage. Real credentials live in Vault dynamic secrets (
plugins/auth/vault_dynamic). Leases are scoped to the workflow and revoked on context exit. Credential bundles never enter evidence files. - Plugin contract drift. The registry rejects any plugin that does not inherit the right ABC or omits the
simulatedflag. - Agent escape. LLM-backed agents can only call read-only tools, only those listed in their per-role allow-list, and only via the runtime's
SafetyGate. Tools cannot be registered withoutread_only = True.
Things we explicitly do not protect against (yet)
- Compromise of the host running the harness. Treat the harness host the same way you'd treat a network management station: hardened, monitored, in a privileged management VLAN.
- Insider abuse with valid credentials and approval rights. Approval-chain enforcement and audit signing make abuse visible after the fact, but the harness is not a substitute for least-privilege role design.
Signing-key custody
The harness uses two distinct keys: one for evidence bundles, one for change approvals. They are intentionally separate so rotating or compromising one does not invalidate or forge the other.
Default custody (dev / demo): both keys are file-backed HMAC-SHA256 secrets auto-generated on first use under var/keys/ (0600 permissions, 32 random bytes). Deterministic across processes on the same host. Suitable for local development, CI, and single-operator demos — not production.
Production custody (recommended):
- Evidence signing — supply a strong secret via
NETOPS_EVIDENCE_HMAC_SECRET(orNETOPS_EVIDENCE_HMAC_KEY_PATH) managed by your secret store, or wireEd25519Signeragainst a Vault transit key. SetNETOPS_EVIDENCE_REQUIRE_CONFIGURED_KEY=1to disable the dev-key fallback and force explicit configuration. - Approval signing — HMAC is acceptable for single-tenant trust; configure via
NETOPS_APPROVAL_HMAC_SECRETorNETOPS_APPROVAL_HMAC_KEY_PATH. For multi-party trust, switch to per-approver Ed25519 keys: approver private keys live with the approver (HSM / YubiKey / Vault transit), only public keys are loaded into the server'sSignerKeyringat bootstrap. The server only verifies — it cannot forge.
The evidence_require_configured_key flag applies to both signers; one switch flips the whole harness into strict-keys mode.
Hardening checklist for production
NETOPS_API_AUTH_MODE=hmac(or OIDC, when wired) — neverdev.- Set
NETOPS_EVIDENCE_HMAC_SECRET(or key path) to a strong secret managed by your secret store, or wireEd25519Signeragainst a Vault transit key. - Set
NETOPS_APPROVAL_HMAC_SECRET(or key path) for single-tenant approvals, or load per-approver Ed25519 public keys into the harness's approval keyring at bootstrap. - Set
NETOPS_EVIDENCE_REQUIRE_CONFIGURED_KEY=1to disable the dev-key fallback for both signers. - Set
config.devices.iosxe.mode = "real"only when the Vault dynamic adapter is configured and the policy file has the right TTLs. - Run
verify_evidence.pyon a schedule and alert on any chain break. - Restrict the API behind a reverse proxy with mTLS where possible.