From cf0a37e0c0ed27ce86c4cd25f7565014417f14f4 Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Thu, 27 Aug 2026 12:12:04 -0400 Subject: [PATCH 01/10] =?UTF-8?q?=F0=9F=93=96=20Add=20KubeStellar=20Hive?= =?UTF-8?q?=20security=20self-assessment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the CNCF TAG-Security self-assessment for KubeStellar Hive under projects/kubestellar/sub-projects/hive/security-assessment/, alongside the existing Console assessment. Hive orchestrates fleets of AI coding agents that autonomously maintain software projects — filing issues, opening pull requests, reviewing, and at high autonomy levels merging. The security model is therefore unusual for a CNCF project: it runs model output with credentials that can write to source repositories, so the assessment focuses on the boundaries that contain that. Covered: the ACMM autonomy levels and agent mode ladder that gate write and merge capability, ioscan prompt-injection scanning of untrusted input, the MITM proxy enforcing network egress rules, GitHub App credential handling, the append-only audit log that provides attribution, and the private vulnerability reporting process. The assessment states known weaknesses rather than omitting them, including that ioscan's default fail mode is open, that agents share a container rather than being sandboxed per run, and that the project currently has a single maintainer. It also records that no third-party security audit or penetration test has been performed. Source document: https://github.com/kubestellar/hive/blob/v4/src/docs/security-self-assessment.md Relative links from the source have been rewritten to absolute Hive URLs so they resolve from this repository. Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 552 ++++++++++++++++++ 1 file changed, 552 insertions(+) create mode 100644 projects/kubestellar/sub-projects/hive/security-assessment/self-assessment.md diff --git a/projects/kubestellar/sub-projects/hive/security-assessment/self-assessment.md b/projects/kubestellar/sub-projects/hive/security-assessment/self-assessment.md new file mode 100644 index 000000000..664d02dbb --- /dev/null +++ b/projects/kubestellar/sub-projects/hive/security-assessment/self-assessment.md @@ -0,0 +1,552 @@ +# Hive Security Self-Assessment + +This document follows the [CNCF TAG-Security self-assessment +template](https://tag-security.cncf.io/community/assessments/guide/self-assessment/) +and is submitted as a required artifact of Hive's CNCF Incubation application. + +> **Scope:** This assessment covers **[kubestellar/hive](https://github.com/kubestellar/hive)** only — the AI agent orchestration system and its hub/spoke deployment. It does **not** cover [KubeStellar Core](https://github.com/kubestellar/kubestellar), the multi-cluster orchestration control plane, or [KubeStellar Console](https://github.com/kubestellar/console), which has its [own self-assessment](../../console/security-assessment/self-assessment.md). +> +> **Canonical source:** this document is maintained in the Hive repository at [`src/docs/security-self-assessment.md`](https://github.com/kubestellar/hive/blob/v4/src/docs/security-self-assessment.md). Corrections should be made there and mirrored here. + +It complements, and deliberately does not duplicate, three existing security +documents in the Hive repository: + +- [security-threat-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-threat-model.md) — attacker-oriented + view: assets, trust boundaries, threat actors, defense layers, residual + risks. +- [security-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-model.md) — operator/evaluator-oriented view: + the seven enforcement layers (dashboard auth, spoke auth, credential + isolation, sandboxing, GitHub blast-radius controls, hub↔spoke channel, + hosted-platform isolation) with file/line evidence for each. +- [security.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security.md) — log-scrubbing and secret-redaction + implementation notes. + +Where this document repeats a claim from those pages, it cites the same +evidence rather than re-deriving it. Sections below cite `path:line` against +the Hive repository's `v4` branch (`src/` prefix; commit `327969b0` at time of +writing) wherever a specific mechanism is asserted. + +## Metadata + +| | | +|---|---| +| Assessment Stage | Complete | +| Software | [kubestellar/hive](https://github.com/kubestellar/hive) | +| Security Provider | No — Hive is not itself a security product. It is an agent-orchestration platform whose core value proposition includes constraining the blast radius of the AI agents it runs; see [Overview](#overview) below. | +| Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `src/bin/`, 45 scripts per [`bin/README.md`](https://github.com/kubestellar/hive/blob/v4/bin/README.md)) | +| SBOM | Not currently generated. Container image builds explicitly disable provenance/SBOM attestations (`sbom: false` in `.github/workflows/docker.yml:134,177,349,454`, citing issue #3760 as the reason). This is a known gap — see [Open questions](#open-questions--not-yet-assessed). | +| Security links | See table below | + +| Doc | URL | +|---|---| +| Security policy / vulnerability reporting | [SECURITY.md](https://github.com/kubestellar/hive/blob/v4/SECURITY.md) | +| Threat model | [security-threat-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-threat-model.md) | +| Security model (operator guide) | [security-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-model.md) | +| Log scrubbing / secret redaction | [security.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security.md) | +| ADRs (architecture decision records) | [adr/README.md](https://github.com/kubestellar/hive/blob/v4/src/docs/adr/README.md) | +| OpenSSF Scorecard workflow | [.github/workflows/scorecard.yml](https://github.com/kubestellar/hive/blob/v4/.github/workflows/scorecard.yml) | + +## Overview + +### Background + +Hive orchestrates fleets of AI coding-agent processes (backends: Claude, +GitHub Copilot, Gemini, Goose, Bob, Agy) that autonomously maintain software +projects hosted on GitHub (and GitHub Enterprise/GitLab/Gitea via the +"Forge App" abstraction) — filing issues, opening pull requests, reviewing +code, and, at the highest autonomy setting, merging. Agents run as CLI +subprocesses inside tmux sessions, in a container or Kubernetes pod, and +authenticate to the source-control provider with a GitHub App installation +token or a PAT. + +A hub/spoke topology lets one central hub coordinate many independent "spoke" +hive deployments (self-hosted or platform-hosted), each spoke typically +governing one or a handful of repositories. + +The defining security property of this project is that the thing being +orchestrated — output from a large language model reading attacker-reachable +GitHub content — is treated as **untrusted input carrying write-capable +credentials to source repositories**. This is not a hypothetical: any public +issue, PR, comment, or label on a governed repository is potential agent +input, and agents that reach the higher autonomy tiers can push code and open +pull requests under real (scoped) GitHub credentials. The project's security +posture is therefore built around the principle stated at the top of +[security-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-model.md): *"if a human would give the same +answer every time, it belongs in infrastructure, not in a prompt."* Enforcement +is intended to sit in deterministic Go/shell code — a network proxy, a token +scope, a file permission — rather than in an instruction the model is asked to +obey. + +### Actors + +- **Repository maintainer / hive operator** — configures ACMM autonomy level, + which repositories are governed, which agents run, and credential sources + (GitHub App vs. PAT, inference backend keys). +- **AI coding agents** — CLI subprocesses that read issues/PRs, propose or + make changes, and (depending on mode) open PRs, comment, or merge. +- **Public GitHub users** — anyone who can open an issue, comment, or PR on a + governed repository; from Hive's perspective their text is untrusted input + that reaches agent prompts. +- **Contributors via ClankeR relay** — external contributors who donate + compute by running an agent against a hive's queue over a relay protocol + (see [contributor-relay.md](https://github.com/kubestellar/hive/blob/v4/src/docs/contributor-relay.md)). +- **Hub operators / SaaS platform operators** — run the central hub that + coordinates registered spokes and, for hosted spokes, provisions + infrastructure and injects GitHub App credentials. +- **Dashboard/API/terminal users** — humans with read, read-write, merger, or + owner-level access to a spoke's dashboard, per `security-model.md` Layer 1/2. + +### Actions + +- Agents read GitHub issues, PRs, comments, labels, and diffs (untrusted text + boundary). +- Agents are "kicked" (launched) with a constructed prompt built from that + text plus repository/task context. +- Agents call GitHub through a CLI wrapper whose outbound HTTPS traffic is + force-redirected through an in-pod MITM proxy that enforces per-mode policy + (`src/pkg/proxy/rules.go`). +- A deterministic pre-kick pipeline (`run-pipeline.sh`) enumerates and + classifies work and computes merge eligibility before any agent acts, + narrowing agent discretion over what is actionable. +- Depending on the operator-selected ACMM level (L1–L6), agents may only + observe, may file issues, may open hold-gated PRs, or may merge. +- Hive itself (not the agent) performs the highest-privilege GitHub writes — + PR creation and PR merge — as the App bot, via hard-denied-to-agents relay + paths (`hive-open-pr`, `hive-merge`; deny rules at + `src/pkg/proxy/rules.go:215-226`). +- Every hive-mediated creation is attribution-stamped and audit-logged + (`src/pkg/github/attribution.go`, `src/pkg/dashboard/audit.go`). +- Registered spokes heartbeat operational telemetry (no credentials) to a + central hub; the hub can push configuration (including GitHub App + credentials for hub-provisioned hives) back to a spoke. + +### Goals + +- Constrain what an LLM-driven agent process can do to a real source + repository, independent of what the agent was prompted or prompt-injected + to do, via layered deterministic controls (network proxy, token scoping, + CLI tool-deny, repo allowlist). +- Make every high-impact GitHub write (issue/PR creation, PR merge) happen + through a Hive-mediated, audited, App-bot-authored path rather than a + directly agent-held credential. +- Reduce — not eliminate — prompt-injection risk from untrusted GitHub text + before it reaches an agent prompt (`ioscan`). +- Give operators one legible autonomy dial (ACMM L1–L6) instead of many + independent toggles, so risk posture is auditable and incrementally + raisable. +- Provide an accountability trail (attribution trailers + append-only audit + log) sufficient to answer "which agent/backend/model did this, and when." + +### Non-goals + +- Hive does not attempt to make LLM output itself trustworthy or to fully + solve prompt injection. `ioscan` mitigates known injection shapes; it is + explicitly not a claim of immunity (see [Known weaknesses](#three-most-significant-known-weaknesses)). +- Hive does not sandbox agent code execution at the level of per-run + containers or microVMs today — agents share one container's process + namespace, separated by per-UID isolation, not process/kernel isolation. + This is a documented, open, tracked gap (issue #2804 — see + `security-threat-model.md` "Residual risks and known gaps"). +- Hive does not provide a general-purpose network content firewall. The MITM + proxy inspects `api.github.com` (and, per `src/pkg/proxy/rules.go:78-80`, + `api.linear.app`) traffic; other destinations are tunneled without + inspection (`security-model.md` "Scope and limitations, stated plainly"). +- Hive does not manage the security of the underlying cluster, container + runtime, or the AI provider accounts operators connect (Claude/Copilot/ + Gemini/Goose credentials are used by the CLI as-is; see + `security-model.md` Layer 3 "Honest scope"). + +## Self-assessment use + +This self-assessment is created by the Hive maintainers to perform an initial +evaluation of the project's security posture as part of the CNCF Incubation +application process. It is not a substitute for a third-party audit or +penetration test — neither has been performed on this project to date (see +[Security issue resolution](#security-issue-resolution)). TAG-Security and +the CNCF community may use it to assess Hive for Incubation and may request +a joint or independent assessment building on it. This document reflects the +project's understanding of its own architecture at the time of writing and +carries no warranty; it should not be relied upon exclusively to assess a +production deployment's risk without independent review. + +## Security functions and features + +### Critical security components + +These are the components whose failure would most directly let an attacker +turn untrusted GitHub content, or a compromised agent, into unauthorized +repository writes: + +1. **MITM egress proxy and ACMM policy rules** + (`src/pkg/proxy/rules.go`, `src/pkg/proxy/github_proxy.go`). All outbound + `:443` traffic from agent processes is force-redirected (iptables + `REDIRECT`, requiring `CAP_NET_ADMIN`) through an in-pod proxy that + terminates TLS for `api.github.com` (and `api.linear.app`) and evaluates + every REST method+path and GraphQL mutation against a first-match rule + table keyed to the agent's ACMM mode (`rules.go:122-178`). Unmatched + operations deny by default (`AllowedByModeCaps`, `rules.go:249-263`). + Direct PR creation (`POST /pulls`) and direct PR merge + (`PUT /pulls/{n}/merge`) are **hard-denied for every mode** + (`rules.go:215-226`, CWE-863 mitigation) — an agent at any autonomy level, + however prompted, cannot call these REST routes; it must go through + `hive-open-pr` / `hive-merge`, which run as Hive itself (App-bot + credentials, SHA-pinned merge-eligibility binding). GraphQL mutations that + merge or create/write PRs are classified by regex + (`graphQLMergeMutationRe`, `graphQLPRWriteMutationRe`, `rules.go:328-338`) + and required to meet the same mode floor as their REST equivalents, closing + a GraphQL bypass of the REST rule table. + +2. **`ioscan` untrusted-input scanner** + (`src/pkg/ioscan`, `src/docs/ioscan.md`). Scans GitHub issue/PR/label/ + author/comment text before it enters an agent kick. Deterministic rules + (Unicode-steganography normalization, base64 decode-and-rescan, + prompt-injection phrasing, dangerous-directive and secret-shape detection) + are always the floor when enabled; blocked text is replaced with a visible + `[ioscan: content withheld — ...]` marker rather than silently dropped or + passed raw. An optional LLM-judge classifier + (`ioscan.classifier.enabled`, default `false`) adds semantic + plain-English-injection detection on top. **Enabled by default** + (`ioscan.enabled: true` is the default per `ioscan.md:9`). + +3. **Per-agent scoped GitHub App tokens and mode-tiered credential issuance** + (per `security-model.md` Layer 5). Advisory-mode agents receive + read-only, no-issue-write tokens; mid-tier agents get issue-write-only + tokens with no code access; only trusted tiers get contents/PR write. The + full shared installation token is never placed in an agent's environment. + +4. **Attribution and audit trail** + (`src/pkg/github/attribution.go`, `src/pkg/dashboard/audit.go`). Every + hive-mediated GitHub creation (PR, issue, comment, merge, review) is + stamped with a visible trailer (`— hive: agent=... backend=... model=...`, + `attribution.go:168-184`) and recorded in an append-only audit log + (`/data/audit.jsonl`, `dashboard/audit.go:22`) regardless of the trailer + toggle (`attribution.go:290-295`). This is the accountability substrate an + operator or incident responder uses to answer "which agent/backend/model + produced this." + +5. **ACMM autonomy-level gating** (`src/pkg/config/packs/level-{1..6}.yaml`, + ADR-0003). A single human-selected level (L1–L6) maps deterministically to + per-agent mode, which in turn drives prompt templates, credential scope, + CLI `--deny-tool`/`--disallowed-tools` flags, and the proxy rule table + above — the same signal enforced in four independent places rather than + one toggle an attacker need only defeat once from the *outside*, though + see the [three most significant weaknesses](#three-most-significant-known-weaknesses) + for what this design choice trades away. + +6. **Forced egress + in-container privilege model** + (`security-model.md` "Forced proxy egress and CAP_NET_ADMIN", "In-container + privilege model"). `su-exec` is the sole setuid binary shipped by Hive, + locked to mode `4750 root:hive-launch` and enforced by a build-time + contract script (`src/scripts/check-suid-contract.sh`) plus a + boot-time inventory check (`src/deploy/test_image_suid_inventory.sh`). + Eleven base-image setuid/setgid binaries inherited from `node:26-slim` were + found world-executable and are stripped in the same build step — a + concrete example of the project auditing its own base image rather than + trusting it by default. + +### Security relevant components + +- **Trajectory review** (`src/docs/trajectory-review.md`) — a second model + periodically compares a running agent's stated intent against a bounded + transcript tail and can pause/alert on divergence. Explicitly semantic + oversight, not a structural control, and fails open on reviewer outage + (per `security-threat-model.md` residual risks). +- **Token budget** — a seven-day rolling token budget that suppresses kicks + on exhaustion, limiting denial-of-wallet from a runaway or compromised + agent loop. +- **Log scrubbing** (`src/pkg/logscrub`, `security.md`) — redacts recognized + GitHub token prefixes (`ghs_`, `ghp_`, `gho_`, `github_pat_`) and JWT-shaped + strings from Hive's own structured log output. Explicitly pattern-based, + not a general secret scanner; does not cover agent CLI stdout/terminal + transcripts unless routed through Hive's logger. +- **Ed25519-only session/SSO verification** (`security-model.md` "Sessions + and SSO are Ed25519-only") — the legacy HMAC session-cookie lane and + fleet-wide shared heartbeat bearer were both removed in v4; a spoke + lacking a verification key fails closed (HTTP 503) rather than falling + back to a weaker check. +- **Master-key generational rotation** with a bounded dual-generation + acceptance window (default 7 days) for sessions/heartbeats/SSO, and no + dual lane at all for terminal/invite keys (`security-model.md` "Master key + rotation"). +- **Supply-chain pinning** — base images and CI actions pinned by digest/SHA + (`src/Dockerfile:8,50,78`; `actions/checkout@3d3c42e...` in + `.github/workflows/docker.yml:85,280,318`); `npm install --ignore-scripts` + for all global AI-CLI installs. +- **OpenSSF Scorecard** — runs weekly and on push to `main`/`v4` + (`.github/workflows/scorecard.yml`), via a shared reusable workflow pinned + by commit SHA. + +## Project compliance + +Hive does not currently hold any formal security certification (e.g. +FIPS, Common Criteria, SOC 2) and makes no claim to one. Relevant +project-level compliance signals: + +- **OpenSSF Scorecard**: automated, runs weekly (`scorecard.yml`); results + are public via the Scorecard badge/API. No specific score floor is gated + in CI at present. +- **DCO (Developer Certificate of Origin)**: enforced for human contributors + via `copilot-dco.yml` and is a stated policy requirement for agent-authored + commits (`git commit -s`) per `security-model.md` Layer 5 — described there + as *"policy-driven inside hive; enforce it repo-side (DCO check) for a hard + guarantee,"* i.e. Hive asks agents to sign off but the hard gate is a + repo-side branch-protection setting the operator must also enable. +- **License**: Apache License 2.0 (`LICENSE`), OSI-approved, CNCF-preferred. +- **No formal SBOM** is currently attached to release artifacts (see + [Metadata](#metadata) and [Open questions](#open-questions--not-yet-assessed)). + +## Secure development practices + +### Development pipeline + +- **Language and structure**: Go (`src/`, `go 1.25.6` per `src/go.mod:3`) for + the core dashboard/hub/proxy/scheduler/agent-orchestration code; a JS + dashboard UI served inline (no separate SPA build step); Python/Shell for + the deterministic pre-kick pipeline (45 scripts, indexed in + `bin/README.md`). +- **Branch model**: `v4` is the sole actively maintained line; + `v2` was retired in August 2026 (`src/docs/README.md` header, `migration-v2-v4.md`). +- **CI gating**: PR-triggered test execution runs from + `.github/workflows/v2-tests.yml` (name is a historical artifact of the + branch-rename; it is the workflow that gates `v4` PRs) as a sharded + `go test -short -race -count=1` run, with an hourly full-suite monitor in + `coverage-hourly.yml` that additionally auto-files an issue on a coverage + regression. Coverage floors are intentionally duplicated between the two + workflows with an in-repo comment instructing both be kept in sync + (`coverage-hourly.yml:15-18`) — a manual-sync risk noted here rather than + hidden. +- **Container build**: multi-stage `src/Dockerfile`, digest-pinned base + images (`golang:1.27-alpine@sha256:...`, `node:26-slim@sha256:...` ×2), a + build-time SUID-contract check that fails the build on any unexpected + setuid/setgid binary, and checksum-verified tool downloads (tmux, ttyd, + `gh`, goose, `su-exec`). +- **No SBOM/provenance attestation** is attached to built images — explicitly + disabled (`sbom: false`, citing issue #3760) rather than merely absent by + omission. Not yet assessed whether #3760 documents a planned reintroduction. +- **Single approver**: `OWNERS` lists one approver and one reviewer + (`clubanderson`) for the whole repository at time of writing — see + [Known weaknesses](#three-most-significant-known-weaknesses) below. +- **CODEOWNERS**: `.github/CODEOWNERS` covers security-sensitive paths + (Dockerfiles, workflows, deploy manifests, launch scripts, key/cookie code) + but is explicitly **advisory only** — "Require review from Code Owners" is + not enabled in branch protection, a deliberate choice documented in + `security-model.md:155` because the repository's automation merges green + PRs without mandatory human review. This is a policy choice the project + states plainly rather than obscures, but it is a real gap between what + CODEOWNERS suggests and what branch protection enforces. + +### Communication channels + +- **Internal**: GitHub issues/PRs/discussions on the `kubestellar/hive` + repository; the project is largely maintained by autonomous agent fleets + operating under the same ACMM framework the software implements + (i.e., Hive is substantially self-hosting — its own maintenance PRs are + frequently agent-authored, subject to the same guardrails described in this + document). +- **Inbound**: public GitHub issues/PRs are the primary inbound channel; + private vulnerability reports go through GitHub Security Advisories per + `SECURITY.md`. +- **Outbound**: release notes via `CHANGELOG.md`; no separate mailing list or + Slack channel is asserted in this assessment (not verified — see + [Open questions](#open-questions--not-yet-assessed)). + +### Ecosystem + +Hive is a KubeStellar-organization project and interoperates with, but does +not depend on: GitHub/GitHub Enterprise/GitLab/Gitea (via the "Forge App" +abstraction), several AI coding-agent CLI backends (Claude Code, GitHub +Copilot CLI, Gemini, Goose, Bob/bobshell, Agy), and self-hosted inference +gateways (LiteLLM, vLLM, llm-d, watsonx) reached only through an in-pod +credential-translating proxy (`security-model.md` Layer 3). It is +independent of any single cloud provider or AI vendor. + +## Security issue resolution + +### Responsible disclosures process + +Vulnerability reports are handled through **GitHub private vulnerability +reporting** (Security tab → "Report a vulnerability"), not public issues, PRs, +or discussions, per [`SECURITY.md`](https://github.com/kubestellar/hive/blob/v4/SECURITY.md). +Reporters are asked for affected component/branch/commit, description and +impact, reproduction steps, and any supporting logs/PoC/config. + +**Vulnerability response process**: the stated target is acknowledgement +within **5 business days** (`SECURITY.md` "What to Expect"), followed by +investigation/confirmation, a coordinated fix and disclosure timeline, and +optional reporter credit. There is no published CVSS-scoring policy, no +published maximum time-to-fix SLA, and no dedicated security response team — +response capacity is effectively the single listed approver +(`OWNERS: approvers: [clubanderson]`). This is stated plainly, not implied: +see [Known weaknesses](#three-most-significant-known-weaknesses). + +### Incident response + +No formal, published incident-response runbook specific to a security +incident (as distinct from operational incidents) was found in this +repository at assessment time. Related but not equivalent: +[`docs/HUB_DISASTER_RECOVERY.md`](https://github.com/kubestellar/hive/blob/v4/docs/HUB_DISASTER_RECOVERY.md) +covers hub-level disaster recovery (backup/restore, spoke fleet recovery, +operator communication), and the master-key rotation flow +(`security-model.md` "Master key rotation") gives an operator a mechanism to +revoke and replace compromised key material fleet-wide without a full +re-provision. Neither is a substitute for a documented incident-response +plan naming roles, communication SLAs, and post-incident review for a +security event specifically. This gap is recorded in +[Open questions](#open-questions--not-yet-assessed). + +## Three most significant known weaknesses + +Stated here explicitly, and cross-referenced to the existing threat model, +because a self-assessment that only lists strengths is not credible: + +1. **Prompt injection is a fundamental, unsolved risk class for this + architecture — mitigated, not eliminated.** Any public GitHub issue, PR, + comment, label, or author field is a potential injection vector into an + agent's prompt (`security-threat-model.md` "Trust boundaries": *"Public + issue authors can place arbitrary text in titles, labels, bodies, and + comments that Hive may include in a kick"*). `ioscan`'s deterministic + rules and optional semantic classifier reduce this materially, but the + **default `ioscan.fail_mode` is `open`** (`ioscan.md:11` — *"open (default) + redacts"*), meaning a scanner outage, timeout, or classifier failure fails + toward continuing to process input rather than halting it. The semantic + (LLM-judge) classifier layer is explicitly **fail-open on errors/timeouts + by design** (`ioscan.md:26`, ADR-0008: *"Classifier failures and budget + exhaustion fail open"*) so a reviewer outage cannot itself become a + scheduler outage — a deliberate availability/security tradeoff the project + documents rather than hides. The deterministic-rules floor and the + hard-deny network relays for PR create/merge are the parts of the defense + that do not depend on any model call succeeding; the semantic layer is + explicitly the part that can silently degrade. `security-threat-model.md` + states this directly: *"ioscan semantic classification is optional and + fail-open... it intentionally fails open on model errors/timeouts to avoid + turning reviewer outages into scheduler outages."* + +2. **Shared-container execution is a materially weaker isolation boundary + than per-run sandboxing, and this is an open, tracked gap.** Agents run as + separate Unix UIDs inside one Hive container/pod, not in separate + containers or microVMs. Per-UID separation (`security-model.md` Layer 4) + stops one agent from attaching to another's tmux session or reading its + GitHub token file, but it does not provide the isolation guarantees a + compromised or maliciously-instructed agent process would need to be + contained against, e.g., host/kernel-level attack surface shared with + every other agent in the pod. `security-threat-model.md` names this + directly under "Residual risks and known gaps": *"Shared-container + execution remains a material risk... it is not equivalent to per-run + containers or microVMs,"* tracked in open issue + [#2804](https://github.com/kubestellar/hive/issues/2804), which — per the + same doc — also proposes moving live GitHub write credentials out of the + agent sandbox entirely (*"current agents can still need live credentials + to push/open PRs"*). Until #2804 lands, a compromised agent process that + evades the network/token controls still executes inside the same + container as every other agent on that spoke. + +3. **Single-maintainer security response capacity, with advisory-only code + ownership enforcement.** `OWNERS` lists exactly one approver and one + reviewer for the entire repository (`clubanderson`) — verified in + `OWNERS` at the root of the `v4` worktree. `SECURITY.md`'s 5-business-day + acknowledgement target and the private-disclosure process are real + commitments, but they rest on one person's availability with no stated + backup or escalation path, and no published SLA for time-to-fix or + time-to-disclosure beyond "we ask that you give us a reasonable + opportunity to remediate." Compounding this, + `.github/CODEOWNERS` — which does cover security-sensitive paths + (Dockerfiles, CI workflows, deploy manifests, launch scripts, key/cookie + handling code) — is **not enforced** by branch protection today; the + project states this is deliberate because its own automation merges green + PRs without mandatory human review (`security-model.md:155`). The net + effect: a change to, say, the MITM proxy's deny-rule table or the SUID + contract script can merge on green CI without a human security reviewer + in the loop, mitigated only by the coverage/test gates and the fact that + much of the review burden is itself carried by the same agent-review + guardrails this document describes (a degree of "the system watching + itself" that is architecturally interesting but not equivalent to + independent human review capacity). This combination — one human in the + loop for both ongoing code review and vulnerability response — is the + single largest institutional (as opposed to technical) risk this + assessment identifies, and is exactly the kind of gap CNCF Incubation + review should weigh: it is a bus-factor and response-capacity risk, not a + code defect. + +A secondary, narrower point worth surfacing alongside the three above: the +**audit log's retention is size-triggered, not time-triggered** — rotation +occurs at 5 MB with 3 backups retained +(`src/pkg/dashboard/audit.go:23-24`, `auditMaxSizeMB = 5`, +`auditMaxBackups = 3`; a 90-day `auditMaxAgeDays` cap also applies but only +prunes files already past the size-based rotation). On a busy hive with many +audited actions per day, the effective lookback window this provides an +incident responder can be materially shorter than 90 days; on a quiet hive it +can be much longer. This is a real, if secondary, forensic-capability limit +on the accountability mechanism this document otherwise credits as a +strength. + +## Appendix + +### Known issues over time + +No CVEs have been filed against this project to date. No third-party +security audit or penetration test has been performed. This is stated +plainly rather than implied by omission: any future reader should treat the +absence of reported CVEs as reflecting a young project without external +audit coverage, not as an implicit clean bill of health under adversarial +review. The security-relevant hardening changes referenced by number +throughout `security-threat-model.md` (e.g. #2760, #2747, #2670, #2680, +#2666, #2805, #2754, #2756, #2762, #2771, #2758, #2755, #2662) represent +maintainer-identified and maintainer-fixed hardening work during v4 +development, not externally reported vulnerabilities. + +### Open SSF best practices + +An [OpenSSF Scorecard](.github/workflows/scorecard.yml) workflow runs weekly +against the repository. This assessment does not reproduce the current +numeric score here (it changes over time and is available live via the +Scorecard badge/API); a reviewer should pull the current score rather than +rely on a number frozen at the time of this document's writing. The project +has not pursued OpenSSF Best Practices Badge ("CII Best Practices") +certification at time of writing — not yet assessed whether this is planned. + +### Case studies + +Not applicable — Hive does not currently publish named case studies of +production deployments in the Hive repository. (Not the same claim as "Hive has +no production users" — simply that no case-study document exists to cite +here.) + +### Related projects / vendors + +Hive is part of the [KubeStellar](https://github.com/kubestellar) CNCF +Sandbox project family. It interoperates with, but is not a vendor +dependency of: GitHub/GitHub Enterprise/GitLab/Gitea, and multiple AI CLI +backend vendors (Anthropic Claude Code, GitHub Copilot CLI, Google Gemini, +Block Goose, IBM Bob). See [landscape.md](https://github.com/kubestellar/hive/blob/v4/docs/landscape.md) +for a maintained comparison against nearby agentic-orchestration tools. + +## Open questions / not yet assessed + +Items this assessment could not verify from the repository alone, listed +explicitly rather than guessed at: + +- Whether issue #3760 (cited as the reason SBOM/provenance attestation is + disabled on container builds) documents a planned path to re-enabling SBOM + generation, or is a permanent decision. +- Whether any external channel (mailing list, Slack, Matrix) exists for + security-relevant project communication beyond GitHub issues/PRs and + private security advisories. +- Whether a formal, security-specific incident-response runbook (as distinct + from the disaster-recovery runbook at `docs/HUB_DISASTER_RECOVERY.md`) + exists outside the Hive repository (e.g., in an internal-only document) — + none was found in the public repository. +- Whether the project intends to pursue OpenSSF Best Practices Badge + certification. +- The current numeric OpenSSF Scorecard result — intentionally not quoted + here since it changes independently of this document; consult the live + badge/workflow output. +- Whether any prior informal security review (e.g., a maintainer's own + adversarial testing beyond what is documented in the ADRs and threat + model) occurred without producing a public artifact. This assessment + treats "no third-party audit" as accurate based on the absence of any + audit report in the repository, but cannot rule out unpublished internal + review. +- Whether `.github/CODEOWNERS` enforcement (branch-protection "Require + review from Code Owners") is planned to be enabled once the project has + more than one active human maintainer, or is intended to remain advisory + indefinitely regardless of maintainer count. From 9baa7b6e53b1ea01f146054f471b8f64c0e0dc29 Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Wed, 9 Sep 2026 11:56:13 -0400 Subject: [PATCH 02/10] Move Hive self-assessment to its own project directory Hive was transferred out of the KubeStellar org to its own vendor-neutral org, hivecommons, on 2026-09-03, and is applying to Sandbox as an independent project (cncf/sandbox#516). It is no longer a KubeStellar subproject, so the assessment moves from projects/kubestellar/sub-projects/hive/ to projects/hive-commons/. - Rewrite all kubestellar/hive source links to hivecommons/hive - Reframe scope, ecosystem, and related-projects sections: KubeStellar is now described as Hive's origin and first production adopter rather than its host org - Correct "Incubation application" to Sandbox application (#516) - Point the sibling Console assessment link at an absolute URL, since the previous relative path no longer resolves from the new location - Fix a pre-existing broken link: docs/landscape.md to src/docs/landscape.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) rename projects/{kubestellar/sub-projects/hive => hive-commons}/security-assessment/self-assessment.md (91%) diff --git a/projects/kubestellar/sub-projects/hive/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md similarity index 91% rename from projects/kubestellar/sub-projects/hive/security-assessment/self-assessment.md rename to projects/hive-commons/security-assessment/self-assessment.md index 664d02dbb..8acfc5843 100644 --- a/projects/kubestellar/sub-projects/hive/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -2,23 +2,24 @@ This document follows the [CNCF TAG-Security self-assessment template](https://tag-security.cncf.io/community/assessments/guide/self-assessment/) -and is submitted as a required artifact of Hive's CNCF Incubation application. +and is submitted as a supporting artifact of Hive Commons' CNCF Sandbox +application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). -> **Scope:** This assessment covers **[kubestellar/hive](https://github.com/kubestellar/hive)** only — the AI agent orchestration system and its hub/spoke deployment. It does **not** cover [KubeStellar Core](https://github.com/kubestellar/kubestellar), the multi-cluster orchestration control plane, or [KubeStellar Console](https://github.com/kubestellar/console), which has its [own self-assessment](../../console/security-assessment/self-assessment.md). +> **Scope:** This assessment covers **[hivecommons/hive](https://github.com/hivecommons/hive)** only — the AI agent orchestration system and its hub/spoke deployment. Hive was incubated as a subproject of KubeStellar and was transferred to its own vendor-neutral org, [hivecommons](https://github.com/hivecommons), on 2026-09-03; this assessment does **not** cover [KubeStellar Core](https://github.com/kubestellar/kubestellar) or [KubeStellar Console](https://github.com/kubestellar/console), which has its [own self-assessment](https://github.com/cncf/toc/blob/main/projects/kubestellar/sub-projects/console/security-assessment/self-assessment.md). > -> **Canonical source:** this document is maintained in the Hive repository at [`src/docs/security-self-assessment.md`](https://github.com/kubestellar/hive/blob/v4/src/docs/security-self-assessment.md). Corrections should be made there and mirrored here. +> **Canonical source:** this document is maintained in the Hive repository at [`src/docs/security-self-assessment.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-self-assessment.md). Corrections should be made there and mirrored here. It complements, and deliberately does not duplicate, three existing security documents in the Hive repository: -- [security-threat-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-threat-model.md) — attacker-oriented +- [security-threat-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-threat-model.md) — attacker-oriented view: assets, trust boundaries, threat actors, defense layers, residual risks. -- [security-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-model.md) — operator/evaluator-oriented view: +- [security-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-model.md) — operator/evaluator-oriented view: the seven enforcement layers (dashboard auth, spoke auth, credential isolation, sandboxing, GitHub blast-radius controls, hub↔spoke channel, hosted-platform isolation) with file/line evidence for each. -- [security.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security.md) — log-scrubbing and secret-redaction +- [security.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security.md) — log-scrubbing and secret-redaction implementation notes. Where this document repeats a claim from those pages, it cites the same @@ -31,20 +32,20 @@ writing) wherever a specific mechanism is asserted. | | | |---|---| | Assessment Stage | Complete | -| Software | [kubestellar/hive](https://github.com/kubestellar/hive) | +| Software | [hivecommons/hive](https://github.com/hivecommons/hive) | | Security Provider | No — Hive is not itself a security product. It is an agent-orchestration platform whose core value proposition includes constraining the blast radius of the AI agents it runs; see [Overview](#overview) below. | -| Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `src/bin/`, 45 scripts per [`bin/README.md`](https://github.com/kubestellar/hive/blob/v4/bin/README.md)) | +| Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `src/bin/`, 45 scripts per [`bin/README.md`](https://github.com/hivecommons/hive/blob/v4/bin/README.md)) | | SBOM | Not currently generated. Container image builds explicitly disable provenance/SBOM attestations (`sbom: false` in `.github/workflows/docker.yml:134,177,349,454`, citing issue #3760 as the reason). This is a known gap — see [Open questions](#open-questions--not-yet-assessed). | | Security links | See table below | | Doc | URL | |---|---| -| Security policy / vulnerability reporting | [SECURITY.md](https://github.com/kubestellar/hive/blob/v4/SECURITY.md) | -| Threat model | [security-threat-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-threat-model.md) | -| Security model (operator guide) | [security-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-model.md) | -| Log scrubbing / secret redaction | [security.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security.md) | -| ADRs (architecture decision records) | [adr/README.md](https://github.com/kubestellar/hive/blob/v4/src/docs/adr/README.md) | -| OpenSSF Scorecard workflow | [.github/workflows/scorecard.yml](https://github.com/kubestellar/hive/blob/v4/.github/workflows/scorecard.yml) | +| Security policy / vulnerability reporting | [SECURITY.md](https://github.com/hivecommons/hive/blob/v4/SECURITY.md) | +| Threat model | [security-threat-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-threat-model.md) | +| Security model (operator guide) | [security-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-model.md) | +| Log scrubbing / secret redaction | [security.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security.md) | +| ADRs (architecture decision records) | [adr/README.md](https://github.com/hivecommons/hive/blob/v4/src/docs/adr/README.md) | +| OpenSSF Scorecard workflow | [.github/workflows/scorecard.yml](https://github.com/hivecommons/hive/blob/v4/.github/workflows/scorecard.yml) | ## Overview @@ -71,7 +72,7 @@ issue, PR, comment, or label on a governed repository is potential agent input, and agents that reach the higher autonomy tiers can push code and open pull requests under real (scoped) GitHub credentials. The project's security posture is therefore built around the principle stated at the top of -[security-model.md](https://github.com/kubestellar/hive/blob/v4/src/docs/security-model.md): *"if a human would give the same +[security-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-model.md): *"if a human would give the same answer every time, it belongs in infrastructure, not in a prompt."* Enforcement is intended to sit in deterministic Go/shell code — a network proxy, a token scope, a file permission — rather than in an instruction the model is asked to @@ -89,7 +90,7 @@ obey. that reaches agent prompts. - **Contributors via ClankeR relay** — external contributors who donate compute by running an agent against a hive's queue over a relay protocol - (see [contributor-relay.md](https://github.com/kubestellar/hive/blob/v4/src/docs/contributor-relay.md)). + (see [contributor-relay.md](https://github.com/hivecommons/hive/blob/v4/src/docs/contributor-relay.md)). - **Hub operators / SaaS platform operators** — run the central hub that coordinates registered spokes and, for hosted spokes, provisions infrastructure and injects GitHub App credentials. @@ -337,7 +338,7 @@ project-level compliance signals: ### Communication channels -- **Internal**: GitHub issues/PRs/discussions on the `kubestellar/hive` +- **Internal**: GitHub issues/PRs/discussions on the `hivecommons/hive` repository; the project is largely maintained by autonomous agent fleets operating under the same ACMM framework the software implements (i.e., Hive is substantially self-hosting — its own maintenance PRs are @@ -352,8 +353,9 @@ project-level compliance signals: ### Ecosystem -Hive is a KubeStellar-organization project and interoperates with, but does -not depend on: GitHub/GitHub Enterprise/GitLab/Gitea (via the "Forge App" +Hive is an independent project in the [hivecommons](https://github.com/hivecommons) +org (transferred out of the KubeStellar org on 2026-09-03, where it was +incubated as a subproject). It interoperates with, but does not depend on: GitHub/GitHub Enterprise/GitLab/Gitea (via the "Forge App" abstraction), several AI coding-agent CLI backends (Claude Code, GitHub Copilot CLI, Gemini, Goose, Bob/bobshell, Agy), and self-hosted inference gateways (LiteLLM, vLLM, llm-d, watsonx) reached only through an in-pod @@ -366,7 +368,7 @@ independent of any single cloud provider or AI vendor. Vulnerability reports are handled through **GitHub private vulnerability reporting** (Security tab → "Report a vulnerability"), not public issues, PRs, -or discussions, per [`SECURITY.md`](https://github.com/kubestellar/hive/blob/v4/SECURITY.md). +or discussions, per [`SECURITY.md`](https://github.com/hivecommons/hive/blob/v4/SECURITY.md). Reporters are asked for affected component/branch/commit, description and impact, reproduction steps, and any supporting logs/PoC/config. @@ -384,7 +386,7 @@ see [Known weaknesses](#three-most-significant-known-weaknesses). No formal, published incident-response runbook specific to a security incident (as distinct from operational incidents) was found in this repository at assessment time. Related but not equivalent: -[`docs/HUB_DISASTER_RECOVERY.md`](https://github.com/kubestellar/hive/blob/v4/docs/HUB_DISASTER_RECOVERY.md) +[`docs/HUB_DISASTER_RECOVERY.md`](https://github.com/hivecommons/hive/blob/v4/docs/HUB_DISASTER_RECOVERY.md) covers hub-level disaster recovery (backup/restore, spoke fleet recovery, operator communication), and the master-key rotation flow (`security-model.md` "Master key rotation") gives an operator a mechanism to @@ -433,7 +435,7 @@ because a self-assessment that only lists strengths is not credible: directly under "Residual risks and known gaps": *"Shared-container execution remains a material risk... it is not equivalent to per-run containers or microVMs,"* tracked in open issue - [#2804](https://github.com/kubestellar/hive/issues/2804), which — per the + [#2804](https://github.com/hivecommons/hive/issues/2804), which — per the same doc — also proposes moving live GitHub write credentials out of the agent sandbox entirely (*"current agents can still need live credentials to push/open PRs"*). Until #2804 lands, a compromised agent process that @@ -513,11 +515,12 @@ here.) ### Related projects / vendors -Hive is part of the [KubeStellar](https://github.com/kubestellar) CNCF -Sandbox project family. It interoperates with, but is not a vendor -dependency of: GitHub/GitHub Enterprise/GitLab/Gitea, and multiple AI CLI +Hive is the flagship of the [Hive Commons](https://hivecommons.dev) project +family and originated as a subproject of [KubeStellar](https://github.com/kubestellar) +(CNCF Sandbox), which remains its first production adopter. It interoperates +with, but is not a vendor dependency of: GitHub/GitHub Enterprise/GitLab/Gitea, and multiple AI CLI backend vendors (Anthropic Claude Code, GitHub Copilot CLI, Google Gemini, -Block Goose, IBM Bob). See [landscape.md](https://github.com/kubestellar/hive/blob/v4/docs/landscape.md) +Block Goose, IBM Bob). See [landscape.md](https://github.com/hivecommons/hive/blob/v4/src/docs/landscape.md) for a maintained comparison against nearby agentic-orchestration tools. ## Open questions / not yet assessed From 62f5e5c417b97c09aec31fec295006a2dfa4405a Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Fri, 11 Sep 2026 09:36:58 -0400 Subject: [PATCH 03/10] Address TAG-Security review: answer the hedged questions Revision 2 in response to the seven review comments on cncf/toc#2286. - Add a deployer-facing threat section: the attack path from a stranger's issue to a repository write, what stands in the way of each concern and what does not, the three settings that determine exposure, and the worst realistic outcome at L6. - State plainly that ioscan has never been red-teamed and has no measured detection rate; recharacterize it as a partial mitigation and credit containment to the network deny rules instead. - Re-scope log scrubbing as log hygiene rather than an exfiltration control, and answer the base64 question directly. Running that question against the canary path surfaced a real defect: the egress check is substring-only, so an encoded canary is not detected, while the input path does decode base64. - Replace the false "Case studies: not applicable" claim with the seven adopters in ADOPTERS.md, three in production, one at ACMM L5/L6 across 43 repositories. - Record that the maintainer roster grew from one to three across three affiliations and that a security response process now exists; restate the remaining risk as unenforced code ownership rather than bus factor. - Correct the SBOM explanation: #3760 is a container-runtime exec defect caused by attestations forcing an OCI index, not an SBOM deprioritization. - Delete the open-questions section and answer every item against the repository, including two answers that are "no". - Commit to the OpenSSF Best Practices badge. Tracking issues filed: hivecommons/hive#6684, #6685, #6686, #6687, #6688. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 503 ++++++++++++++---- 1 file changed, 395 insertions(+), 108 deletions(-) diff --git a/projects/hive-commons/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md index 8acfc5843..99cf34cf3 100644 --- a/projects/hive-commons/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -9,6 +9,23 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > > **Canonical source:** this document is maintained in the Hive repository at [`src/docs/security-self-assessment.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-self-assessment.md). Corrections should be made there and mirrored here. +> **Revision 2 — changes made in response to TAG-Security review +> ([cncf/toc#2286](https://github.com/cncf/toc/pull/2286)).** Seven review +> comments asked, in substance, for the parts the first draft hedged on. Each +> is addressed: +> +> | Review point | Change | +> |---|---| +> | "If I deploy this, what should I worry about?" | New section [If you deploy this, what should you worry about?](#if-you-deploy-this-what-should-you-worry-about) — the attack path stated plainly, a concern/mitigation/non-mitigation table, the three settings that determine exposure, and the worst realistic outcome. | +> | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered: **no red-teaming exists.** Efficacy is now described as unmeasured and partial, with the containment credited to the network deny rules instead. Evaluation tracked in [#6685](https://github.com/hivecommons/hive/issues/6685). | +> | "What is redaction for? What about base64-encoded exfiltration?" | Log scrubbing re-scoped as log hygiene, explicitly **not** an exfiltration control. Running the question against the canary path found a real gap — the egress check is substring-only — now filed as [#6686](https://github.com/hivecommons/hive/issues/6686) and recorded as a known weakness. | +> | "Get an OpenSSF passing badge." | Agreed; being pursued in [#6684](https://github.com/hivecommons/hive/issues/6684). Most passing criteria already met. | +> | "This is a huge risk. Why not mitigate it?" | Half was mitigated: the roster went from **one maintainer to three**, across three affiliations, with a documented security-response process. The unmitigated half — unenforced code ownership — is now stated as the largest remaining process risk, with scoped enforcement tracked in [#6687](https://github.com/hivecommons/hive/issues/6687). | +> | "Looks like AI generated this — you should know the answer." | The "Case studies: not applicable" claim was simply **wrong**: `ADOPTERS.md` lists seven adopters, three in production, one running at ACMM L5/L6 across 43 repositories. Replaced with the real table. | +> | "Go through the open questions and figure them out." | The open-questions section is gone. Every item was run down against the repository and answered in [Questions resolved since first review](#questions-resolved-since-first-review) — including two answers that are "no." | +> +> Net effect: five issues filed ([#6684](https://github.com/hivecommons/hive/issues/6684), [#6685](https://github.com/hivecommons/hive/issues/6685), [#6686](https://github.com/hivecommons/hive/issues/6686), [#6687](https://github.com/hivecommons/hive/issues/6687), [#6688](https://github.com/hivecommons/hive/issues/6688)), one previously-undetected defect found, and several claims corrected against the repository rather than restated. + It complements, and deliberately does not duplicate, three existing security documents in the Hive repository: @@ -35,7 +52,7 @@ writing) wherever a specific mechanism is asserted. | Software | [hivecommons/hive](https://github.com/hivecommons/hive) | | Security Provider | No — Hive is not itself a security product. It is an agent-orchestration platform whose core value proposition includes constraining the blast radius of the AI agents it runs; see [Overview](#overview) below. | | Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `src/bin/`, 45 scripts per [`bin/README.md`](https://github.com/hivecommons/hive/blob/v4/bin/README.md)) | -| SBOM | Not currently generated. Container image builds explicitly disable provenance/SBOM attestations (`sbom: false` in `.github/workflows/docker.yml:134,177,349,454`, citing issue #3760 as the reason). This is a known gap — see [Open questions](#open-questions--not-yet-assessed). | +| SBOM | Not currently attached to images, for a specific and non-obvious reason rather than by oversight. `build-push-action` attaches provenance/SBOM attestations by default, and an attestation can only be carried by an OCI image *index* — which changed the published artifact from a plain manifest to `application/vnd.oci.image.index.v1+json`. That form let a `COPY --from` layer ship an overlayfs metacopy redirect for `/usr/local/bin/hive`, which containerd/k3s and rootless podman present as **non-executable**, crash-looping the image ([#3760](https://github.com/hivecommons/hive/issues/3760), now closed). `provenance: false`/`sbom: false` (`docker.yml:295,346,631,818`) is the fix for that runtime defect. The correct resolution is to generate the SBOM **out-of-band** (e.g. a syft/Trivy step publishing a release artifact) so the image manifest stays plain — tracked in [#6688](https://github.com/hivecommons/hive/issues/6688). | | Security links | See table below | | Doc | URL | @@ -157,6 +174,57 @@ obey. Gemini/Goose credentials are used by the CLI as-is; see `security-model.md` Layer 3 "Honest scope"). +### If you deploy this, what should you worry about? + +The rest of this document is organized by control. This section is organized +by *concern*, because a prospective operator's first question is not "what +mechanisms exist" but "what is the realistic path from a stranger typing +something to something bad happening to my code, and what stands in the way?" + +**The path, stated plainly.** Anyone with a GitHub account can open an issue +or comment on a governed public repository. That text is enumerated by the +pre-kick pipeline, scanned by `ioscan`, and — if it survives — placed into a +prompt handed to a CLI agent that holds a real, if scoped, GitHub credential. +**There is no step in that chain where a human necessarily reads the +attacker's text first.** That is the core exposure, and no amount of layered +control removes it; the controls bound the consequences. + +| Concern | What actually stands in the way | What does *not* | +|---|---|---| +| Attacker text talks an agent into **merging** malicious code | `PUT /pulls/{n}/merge` is **hard-denied for every ACMM mode** at the proxy (`rules.go:215-226`), as is the GraphQL merge mutation. The agent never holds a credential path to merge; `hive-merge` runs as Hive with a SHA-pinned eligibility binding. | `ioscan`. A sufficiently clever prompt defeats a scanner; it does not defeat a rule table the model never sees. | +| Attacker text talks an agent into **opening a PR** with a backdoor | `POST /pulls` is likewise hard-denied for every mode. PR creation goes through `hive-open-pr` as the App bot, attribution-stamped and audit-logged. | Nothing prevents the *content* of a legitimately-created PR from being attacker-influenced. Review it like any other PR. | +| Attacker exfiltrates your **secrets** via the agent | Mode-tiered tokens mean low-tier agents never hold code-write credentials. Optional `ioscan` canaries detect prompt contents echoed into outbound GitHub writes at the proxy. | Canaries are **default-off** and substring-matched — see the [encoding gap](#three-most-significant-known-weaknesses). Non-GitHub egress is tunneled without inspection. | +| Agent burns your **inference budget** in a loop | Seven-day rolling token budget suppresses kicks on exhaustion. | Nothing caps the *rate* within budget. | +| Compromised agent attacks **other agents** on the same spoke | Per-UID separation stops tmux attach and token-file reads. | Shared container/kernel. See weakness #2. | + +**The three settings that actually determine your exposure**, in order: + +1. **Your ACMM level.** At L1–L3 an agent can observe and file issues but + cannot write code; at L6 it can merge. This single dial moves prompt + templates, credential scope, CLI tool-denies and proxy rules together. It + is the control to reason about first, and it is the one an operator + chooses rather than inherits. +2. **Whether the governed repository is public.** A private repository with + trusted collaborators collapses most of the untrusted-input surface. The + threat model above is substantially a *public-repository* threat model. +3. **Whether you enabled `ioscan.canaries` and `fail_mode: closed`.** Both + default to the permissive setting. The defaults favor availability; a + security-sensitive deployment should change them and accept that a + scanner outage then becomes a scheduling outage. + +**What we would tell a new operator.** Start at L1–L3 on a repository you +would not mind an agent filing a bad issue on. Read the attribution trailers +and the audit log for a week — every hive-mediated write is stamped, so this +is cheap. Raise the level only once the agents' actual behavior on *your* +codebase is boring. Do not start at L6 on a public flagship repository. + +**The worst realistic outcome** if every soft control fails and the operator +has set L6: an attacker-influenced pull request is authored and merged by the +App bot, with a full attribution trailer and audit-log entry naming the agent, +backend and model. It is recoverable and traceable, which is the property the +architecture optimizes for — but it is a real bad day, and an operator should +choose an autonomy level with that outcome in mind rather than the happy path. + ## Self-assessment use This self-assessment is created by the Hive maintainers to perform an initial @@ -209,6 +277,34 @@ repository writes: plain-English-injection detection on top. **Enabled by default** (`ioscan.enabled: true` is the default per `ioscan.md:9`). + **How well does it work? Honestly: unmeasured, and it should be read as a + partial mitigation rather than a defense.** No red-team exercise, + adversarial evaluation, or measured detection rate exists for `ioscan` — + the package has 56 unit tests across its rule, Unicode, classifier and + canary paths, but unit tests establish that known shapes are caught, not + that unknown ones are. A prospective user should assume a determined, + encoding-aware attacker defeats it. What `ioscan` reliably does is (a) + raise the cost of the *casual* injection attempt, (b) normalize away an + entire class of invisible-character and homoglyph tricks deterministically, + and (c) produce an auditable record that something was withheld. What + contains the *consequence* of a successful injection is not `ioscan` at + all: it is the hard-denied PR-create/merge relays and the mode-tiered + token scope, neither of which the model can argue with. Operators should + size their trust accordingly, and the project commits to publishing a + red-team evaluation rather than leaving efficacy asserted + ([#6685](https://github.com/hivecommons/hive/issues/6685)). + + **Exfiltration detection (`ioscan.canaries`, default off).** A per-agent + `HIVE-CANARY-<48 hex>` token is planted in the agent's prompt, and the + egress proxy scans outbound GitHub request bodies for it + (`github_proxy.go:1179-1205`): a hit is positive evidence that prompt + contents reached a write, and is audit-logged and — with + `fail_mode: closed` — blocked. Two limits are stated rather than implied: + the match is a literal substring test (`canary.go`, `strings.Contains`), + so **an encoded canary is not detected**, and `git-receive-pack` bodies + are opaque to it, so a push is only stopped when fail-closed is set. Both + are tracked in [Known weaknesses](#three-most-significant-known-weaknesses). + 3. **Per-agent scoped GitHub App tokens and mode-tiered credential issuance** (per `security-model.md` Layer 5). Advisory-mode agents receive read-only, no-issue-write tokens; mid-tier agents get issue-write-only @@ -255,11 +351,30 @@ repository writes: - **Token budget** — a seven-day rolling token budget that suppresses kicks on exhaustion, limiting denial-of-wallet from a runaway or compromised agent loop. -- **Log scrubbing** (`src/pkg/logscrub`, `security.md`) — redacts recognized - GitHub token prefixes (`ghs_`, `ghp_`, `gho_`, `github_pat_`) and JWT-shaped - strings from Hive's own structured log output. Explicitly pattern-based, - not a general secret scanner; does not cover agent CLI stdout/terminal - transcripts unless routed through Hive's logger. +- **Log scrubbing** (`src/pkg/logscrub`, `security.md`) — redacts eight + categories from Hive's own structured log output: GitHub token prefixes + (`ghs_`, `ghp_`, `gho_`, `github_pat_`), JWTs, AWS access-key IDs, + `Bearer` headers, PEM private keys (plain, encrypted and PGP), and Hive + canary tokens (`handler.go:29-36`). + + **What this is for, precisely:** it is *operational hygiene for logs Hive + itself writes* — so that a token appearing in an error string does not end + up in a pasted log snippet, a support bundle, or a CI artifact. **It is not + an exfiltration control and must not be read as one.** It sits on Hive's + logging path, not on the agent's egress path, and it is pattern-based: an + attacker who prompt-injects an agent into emitting a credential in base64, + hex, reversed, or split across tokens defeats it completely, and the + project states that plainly rather than letting the word "redaction" imply + containment. The controls that do bear on that attack are elsewhere and are + also imperfect: mode-tiered token scoping means a low-tier agent has no + code-write credential to leak in the first place; `ioscan`'s canary check + at the proxy catches prompt contents reaching an outbound GitHub write + (but, as noted above, only as a literal substring — the base64 case defeats + it too, and closing that gap is tracked in + [#6686](https://github.com/hivecommons/hive/issues/6686)); and non-GitHub + destinations are tunneled without inspection at all. An operator who needs + a hard guarantee against credential egress should not rely on any of these + and should scope the credentials themselves. - **Ed25519-only session/SSO verification** (`security-model.md` "Sessions and SSO are Ed25519-only") — the legacy HMAC session-cookie lane and fleet-wide shared heartbeat bearer were both removed in v4; a spoke @@ -283,9 +398,22 @@ Hive does not currently hold any formal security certification (e.g. FIPS, Common Criteria, SOC 2) and makes no claim to one. Relevant project-level compliance signals: -- **OpenSSF Scorecard**: automated, runs weekly (`scorecard.yml`); results - are public via the Scorecard badge/API. No specific score floor is gated - in CI at present. +- **OpenSSF Scorecard**: automated, runs weekly and on push to `main`/`v4` + (`scorecard.yml`, via a SHA-pinned reusable workflow in + `hivecommons/infra`); results publish to the repository's code-scanning + alerts. No specific score floor is gated in CI at present. +- **OpenSSF Best Practices Badge**: **not yet held — and being pursued.** At + first review of this assessment the project had not registered, and + TAG-Security's feedback was that a passing badge is achievable + low-hanging fruit whose criteria are things the project should be doing + anyway. The maintainers agree; registration and criteria completion are + tracked in [#6684](https://github.com/hivecommons/hive/issues/6684), and + this document will carry the badge ID and level once awarded rather than a + promise. The substantive prerequisites — OSI license, public VCS, private + vulnerability reporting, documented contribution process, automated test + suite in CI, static analysis, and no known unpatched vulnerabilities — are + already satisfied; what is missing is the registration and self-certification + itself. - **DCO (Developer Certificate of Origin)**: enforced for human contributors via `copilot-dco.yml` and is a stated policy requirement for agent-authored commits (`git commit -s`) per `security-model.md` Layer 5 — described there @@ -293,8 +421,10 @@ project-level compliance signals: guarantee,"* i.e. Hive asks agents to sign off but the hard gate is a repo-side branch-protection setting the operator must also enable. - **License**: Apache License 2.0 (`LICENSE`), OSI-approved, CNCF-preferred. -- **No formal SBOM** is currently attached to release artifacts (see - [Metadata](#metadata) and [Open questions](#open-questions--not-yet-assessed)). +- **No formal SBOM** is currently attached to release artifacts — for the + container-runtime reason explained under [Metadata](#metadata), with the + out-of-band path recorded in + [Questions resolved since first review](#questions-resolved-since-first-review). ## Secure development practices @@ -324,17 +454,32 @@ project-level compliance signals: - **No SBOM/provenance attestation** is attached to built images — explicitly disabled (`sbom: false`, citing issue #3760) rather than merely absent by omission. Not yet assessed whether #3760 documents a planned reintroduction. -- **Single approver**: `OWNERS` lists one approver and one reviewer - (`clubanderson`) for the whole repository at time of writing — see - [Known weaknesses](#three-most-significant-known-weaknesses) below. +- **Maintainer roster**: `OWNERS` lists **three** approvers/reviewers — + Andy Anderson (@clubanderson, IBM), James Reilly (@hanthor, Universal + Blue) and Doug Baggett (@Danathar, independent). This is a change since + this document's first revision, when the roster was one person; the + bus-factor and security-response concerns raised in review were addressed + by growing the committee across three distinct affiliations rather than by + restating the risk. `OWNERS` is required to stay in sync with the + Maintainer Committee table in upstream `GOVERNANCE-HIVE.md`, and the file + says so explicitly, calling drift "a governance drift bug, not a + housekeeping detail." - **CODEOWNERS**: `.github/CODEOWNERS` covers security-sensitive paths - (Dockerfiles, workflows, deploy manifests, launch scripts, key/cookie code) - but is explicitly **advisory only** — "Require review from Code Owners" is - not enabled in branch protection, a deliberate choice documented in - `security-model.md:155` because the repository's automation merges green - PRs without mandatory human review. This is a policy choice the project - states plainly rather than obscures, but it is a real gap between what - CODEOWNERS suggests and what branch protection enforces. + (Dockerfiles, workflows, deploy manifests, launch scripts, key/cookie + code) but is **advisory only** — "Require review from Code Owners" is not + enabled in `v4` branch protection (verified against the live branch + protection API: no required pull-request reviews are configured; one + required status check is). The reason is stated in the file's own header: + the repository's automation merges green PRs, and enforcement would block + it. Two honest consequences follow. First, every path in that file + currently resolves to a single owner (`@clubanderson`) even though three + maintainers now exist — a lag between the governance change and the + ownership file, being corrected. Second, and more important: a change to + the proxy deny-rule table or the SUID contract script can merge on green + CI without a human security reviewer. That is a real gap between what + CODEOWNERS implies and what branch protection enforces, and it is the + project's largest remaining process risk — see + [Known weaknesses](#three-most-significant-known-weaknesses). ### Communication channels @@ -347,9 +492,17 @@ project-level compliance signals: - **Inbound**: public GitHub issues/PRs are the primary inbound channel; private vulnerability reports go through GitHub Security Advisories per `SECURITY.md`. -- **Outbound**: release notes via `CHANGELOG.md`; no separate mailing list or - Slack channel is asserted in this assessment (not verified — see - [Open questions](#open-questions--not-yet-assessed)). +- **Outbound**: release notes via `CHANGELOG.md`. There is deliberately **no + mailing list, Slack, Matrix or Discord channel** for project decisions: + `CONTRIBUTING.md` directs contributors to "discuss design and review + questions in GitHub issues and PRs so decisions remain public and + searchable." (Hive the *product* integrates with Slack/Discord/ntfy for + operator alerting — see `notifications.md` — but that is a feature of the + software, not a project communication channel, and the two should not be + confused.) The practical security consequence is that there is no private + side channel where a vulnerability discussion could happen off-record; + everything is either a public GitHub thread or a private GitHub Security + Advisory. ### Ecosystem @@ -375,26 +528,40 @@ impact, reproduction steps, and any supporting logs/PoC/config. **Vulnerability response process**: the stated target is acknowledgement within **5 business days** (`SECURITY.md` "What to Expect"), followed by investigation/confirmation, a coordinated fix and disclosure timeline, and -optional reporter credit. There is no published CVSS-scoring policy, no -published maximum time-to-fix SLA, and no dedicated security response team — -response capacity is effectively the single listed approver -(`OWNERS: approvers: [clubanderson]`). This is stated plainly, not implied: -see [Known weaknesses](#three-most-significant-known-weaknesses). +optional reporter credit. Who performs that work is now documented: +[`security-response.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-response.md) +establishes that security response is a duty of the **Maintainer Committee** +— there is no separate security team, the committee *is* the response team — +and that any of the three maintainers can receive and triage a report, with +whoever picks up the GitHub Security Advisory notification driving it and +looping in the others for confirmation, severity and disclosure timing. The +page deliberately does not restate the roster, pointing at `OWNERS` instead +so a second list cannot drift. + +Remaining gaps, stated rather than implied: there is **no published +CVSS-scoring policy** and **no maximum time-to-fix SLA** beyond asking +reporters for "a reasonable opportunity to remediate." The acknowledgement +target is a commitment; time-to-fix is not. ### Incident response -No formal, published incident-response runbook specific to a security -incident (as distinct from operational incidents) was found in this -repository at assessment time. Related but not equivalent: -[`docs/HUB_DISASTER_RECOVERY.md`](https://github.com/hivecommons/hive/blob/v4/docs/HUB_DISASTER_RECOVERY.md) -covers hub-level disaster recovery (backup/restore, spoke fleet recovery, -operator communication), and the master-key rotation flow -(`security-model.md` "Master key rotation") gives an operator a mechanism to -revoke and replace compromised key material fleet-wide without a full -re-provision. Neither is a substitute for a documented incident-response -plan naming roles, communication SLAs, and post-incident review for a -security event specifically. This gap is recorded in -[Open questions](#open-questions--not-yet-assessed). +A security-specific response process is documented in +[`security-response.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-response.md) +— who responds, how a report is triaged, and how disclosure is coordinated — +distinct from +[`docs/HUB_DISASTER_RECOVERY.md`](https://github.com/hivecommons/hive/blob/v4/docs/HUB_DISASTER_RECOVERY.md), +which covers hub-level disaster recovery (backup/restore, spoke fleet +recovery, operator communication) and is an operational rather than security +runbook. The master-key rotation flow (`security-model.md` "Master key +rotation") provides the mechanism to revoke and replace compromised key +material fleet-wide without a full re-provision, which is the concrete +containment action most security incidents in this architecture would +require. + +What is documented is roles and handling. What is **not** yet documented is a +post-incident review practice (blameless postmortem, publication commitment) +and user-notification SLAs for a confirmed compromise. Those are real gaps +and are named here rather than papered over. ## Three most significant known weaknesses @@ -442,32 +609,50 @@ because a self-assessment that only lists strengths is not credible: evades the network/token controls still executes inside the same container as every other agent on that spoke. -3. **Single-maintainer security response capacity, with advisory-only code - ownership enforcement.** `OWNERS` lists exactly one approver and one - reviewer for the entire repository (`clubanderson`) — verified in - `OWNERS` at the root of the `v4` worktree. `SECURITY.md`'s 5-business-day - acknowledgement target and the private-disclosure process are real - commitments, but they rest on one person's availability with no stated - backup or escalation path, and no published SLA for time-to-fix or - time-to-disclosure beyond "we ask that you give us a reasonable - opportunity to remediate." Compounding this, - `.github/CODEOWNERS` — which does cover security-sensitive paths - (Dockerfiles, CI workflows, deploy manifests, launch scripts, key/cookie - handling code) — is **not enforced** by branch protection today; the - project states this is deliberate because its own automation merges green - PRs without mandatory human review (`security-model.md:155`). The net - effect: a change to, say, the MITM proxy's deny-rule table or the SUID - contract script can merge on green CI without a human security reviewer - in the loop, mitigated only by the coverage/test gates and the fact that - much of the review burden is itself carried by the same agent-review - guardrails this document describes (a degree of "the system watching - itself" that is architecturally interesting but not equivalent to - independent human review capacity). This combination — one human in the - loop for both ongoing code review and vulnerability response — is the - single largest institutional (as opposed to technical) risk this - assessment identifies, and is exactly the kind of gap CNCF Incubation - review should weigh: it is a bus-factor and response-capacity risk, not a - code defect. +3. **Unenforced code ownership on security-sensitive paths — the + single-maintainer half of this risk has been mitigated; the + branch-protection half has not.** When this assessment was first + submitted, `OWNERS` listed exactly one approver, and TAG-Security review + correctly identified that as a serious risk rather than a footnote. It + has been addressed: the Maintainer Committee now has **three members + across three distinct affiliations** — @clubanderson (IBM), @hanthor + (Universal Blue), @Danathar (independent) — and + `security-response.md` now names the committee as the security response + team with an explicit "whoever picks up the advisory drives it" triage + rule. Bus factor and vendor neutrality both improved as a result, and the + 5-business-day acknowledgement commitment no longer rests on one person's + availability. + + **What remains unmitigated is the enforcement gap, and it is real.** + `.github/CODEOWNERS` covers the security-sensitive paths — Dockerfiles, + CI workflows, deploy manifests, launch scripts, key/cookie handling — but + "Require review from Code Owners" is **not enabled** in `v4` branch + protection, which the live API confirms: no required pull-request reviews + are configured at all. Every path in that file also still resolves to a + single owner, lagging the governance change. The net effect is that a + change to the MITM proxy's deny-rule table — the control this document + credits as the thing an attacker cannot argue with — can merge on green + CI with no human security reviewer. + + **Why it has not simply been turned on.** This is the honest trade at the + center of the project: Hive is substantially self-hosting, and its own + agent fleet merges green PRs. Enabling required code-owner review would + halt that automation repository-wide, which is why `CODEOWNERS` itself + documents the choice in its header rather than leaving it implicit. That + is an explanation, not a justification, and the maintainers do not offer + it as one. The defensible resolution is not "all or nothing" but a + **scoped** enforcement rule covering only the security-critical paths + (proxy rules, SUID contract, workflows, deploy manifests, key handling), + leaving ordinary code paths on the automated merge path. That is tracked + in [#6687](https://github.com/hivecommons/hive/issues/6687), together + with updating `CODEOWNERS` to list all three maintainers so enforcement + is survivable when it lands. + + Until that ships, an evaluator should treat "the deny-rule table is + enforced in code" as true and "the deny-rule table is protected from + unreviewed change" as **not** true, and weight this accordingly. It is + the single largest process (as opposed to technical) risk this assessment + identifies. A secondary, narrower point worth surfacing alongside the three above: the **audit log's retention is size-triggered, not time-triggered** — rotation @@ -481,6 +666,27 @@ can be much longer. This is a real, if secondary, forensic-capability limit on the accountability mechanism this document otherwise credits as a strength. +Two further narrow gaps, surfaced because they were found while responding to +TAG-Security review and it would be poor practice to let review-driven +discoveries go unrecorded: + +- **The canary egress check is not encoding-aware.** `CanaryRegistry.Scan` + tests with `strings.Contains`, so an agent induced to emit its canary + base64-encoded, hex-encoded, reversed, or split across a body passes the + proxy check unflagged — even though `ioscan`'s *input* path does decode + base64 and normalize Unicode before scanning. The asymmetry is an + oversight rather than a decision, and is tracked in + [#6686](https://github.com/hivecommons/hive/issues/6686). Note the control + degrades to "no worse than not having it," not to a false assurance, since + a canary hit is positive evidence and a miss was never treated as proof of + absence. +- **`git-receive-pack` bodies are opaque to canary scanning.** A `git push` + is pack-encoded, so the proxy cannot inspect it for leaked markers; with + `fail_mode: closed` the push is refused outright, and otherwise it + proceeds unscanned (`github_proxy.go:1182`). An operator relying on + canaries should understand that they cover the GitHub *API* egress path, + not the git transport. + ## Appendix ### Known issues over time @@ -498,20 +704,58 @@ development, not externally reported vulnerabilities. ### Open SSF best practices -An [OpenSSF Scorecard](.github/workflows/scorecard.yml) workflow runs weekly -against the repository. This assessment does not reproduce the current -numeric score here (it changes over time and is available live via the -Scorecard badge/API); a reviewer should pull the current score rather than -rely on a number frozen at the time of this document's writing. The project -has not pursued OpenSSF Best Practices Badge ("CII Best Practices") -certification at time of writing — not yet assessed whether this is planned. +An [OpenSSF Scorecard](https://github.com/hivecommons/hive/blob/v4/.github/workflows/scorecard.yml) +workflow runs weekly and on push to `main`/`v4`, publishing to the +repository's code-scanning alerts. This assessment deliberately does not +freeze a numeric score into the text — it moves independently of this +document — and a reviewer should pull the current result. + +**OpenSSF Best Practices Badge: not yet held, and now being pursued.** The +first revision of this document recorded this as "not yet assessed whether +this is planned," which was an evasion; TAG-Security review called it out, +and the answer is that the project had simply not done it. It is planned, and +tracked in [#6684](https://github.com/hivecommons/hive/issues/6684). The +passing-level criteria are largely met already — OSI-approved license +(Apache-2.0), public version-controlled source, documented contribution +process, private vulnerability reporting via GitHub Security Advisories, an +automated test suite gating every PR, static analysis in CI, digest-pinned +dependencies, and no known unpatched vulnerabilities — so the outstanding +work is registration and self-certification rather than engineering. When the +badge is awarded this section will carry its ID and level; until then it +carries the issue number, because a tracked commitment is worth more to a +reviewer than a claim. ### Case studies -Not applicable — Hive does not currently publish named case studies of -production deployments in the Hive repository. (Not the same claim as "Hive has -no production users" — simply that no case-study document exists to cite -here.) +Hive maintains an [`ADOPTERS.md`](https://github.com/hivecommons/hive/blob/v4/ADOPTERS.md) +file with seven organizations, three of them at **Production** maturity. +The security-relevant point is not the count but that these are deployments +where the threat model in this document is live — real repositories, real +credentials, real untrusted public input: + +| Adopter | Use | Maturity | Evidence | +|---|---|---|---| +| [KubeStellar Console](https://github.com/kubestellar/console) | Autonomous maintenance of the Console codebase — triage, fixes, review, merge | Production | Hive's origin adopter | +| [tunaos.org](https://tunaos.org) | Self-hosted hub coordinating two ACMM **L5/L6** spokes across 43 repositories | Production | [#5773](https://github.com/hivecommons/hive/issues/5773) | +| [Project Bluefin](https://github.com/projectbluefin) | Self-managed hive over `projectbluefin/dakota` and related repos | Production | [docs.projectbluefin.io/factory](https://docs.projectbluefin.io/factory/); [#4928](https://github.com/hivecommons/hive/issues/4928), [#6449](https://github.com/hivecommons/hive/issues/6449), [#6450](https://github.com/hivecommons/hive/issues/6450) | +| [Frostyard](https://github.com/frostyard) | Autonomous development operations | Pre-production | | +| [Open Horizon](https://github.com/open-horizon) | Code-consistency standardization and enforcement | Pre-production | | +| [Open Horizon Services](https://github.com/open-horizon-services) | Consistency over community contributions | Pre-production | | +| [Danathar](https://github.com/Danathar) | Autonomous development operations | Pre-production | | + +Two of these are worth a reviewer's attention specifically. **tunaos.org runs +at L5/L6 across 43 repositories** — the autonomy tiers at which agents can +merge — which is the strongest available evidence that the deny-rule and +attribution controls hold up outside the maintainers' own environment. +**Project Bluefin is independently documented by the adopter**, not merely +self-reported here. + +What the project does *not* have is a written security case study — a +narrative of an incident, an attempted injection, or an adopter's own +security evaluation. That would be more useful to TAG-Security than an +adopter table, and its absence is a genuine gap rather than a formatting +choice. The earlier revision of this document said "Not applicable," which +was wrong on the facts and is corrected here. ### Related projects / vendors @@ -523,33 +767,76 @@ backend vendors (Anthropic Claude Code, GitHub Copilot CLI, Google Gemini, Block Goose, IBM Bob). See [landscape.md](https://github.com/hivecommons/hive/blob/v4/src/docs/landscape.md) for a maintained comparison against nearby agentic-orchestration tools. -## Open questions / not yet assessed - -Items this assessment could not verify from the repository alone, listed -explicitly rather than guessed at: - -- Whether issue #3760 (cited as the reason SBOM/provenance attestation is - disabled on container builds) documents a planned path to re-enabling SBOM - generation, or is a permanent decision. -- Whether any external channel (mailing list, Slack, Matrix) exists for - security-relevant project communication beyond GitHub issues/PRs and - private security advisories. -- Whether a formal, security-specific incident-response runbook (as distinct - from the disaster-recovery runbook at `docs/HUB_DISASTER_RECOVERY.md`) - exists outside the Hive repository (e.g., in an internal-only document) — - none was found in the public repository. -- Whether the project intends to pursue OpenSSF Best Practices Badge - certification. -- The current numeric OpenSSF Scorecard result — intentionally not quoted - here since it changes independently of this document; consult the live - badge/workflow output. -- Whether any prior informal security review (e.g., a maintainer's own - adversarial testing beyond what is documented in the ADRs and threat - model) occurred without producing a public artifact. This assessment - treats "no third-party audit" as accurate based on the absence of any - audit report in the repository, but cannot rule out unpublished internal - review. -- Whether `.github/CODEOWNERS` enforcement (branch-protection "Require - review from Code Owners") is planned to be enabled once the project has - more than one active human maintainer, or is intended to remain advisory - indefinitely regardless of maintainer count. +## Questions resolved since first review + +The first revision of this document ended with a list of open questions. That +was a defensible way to ship a draft and an indefensible way to leave one: +TAG-Security review observed, correctly, that these were prompts to the +authors rather than findings for a reader. Each has been run down against the +repository and answered below. Where the answer is "no," it says no. + +- **Does issue #3760 document a path to re-enabling SBOM/provenance?** + Resolved. #3760 is **closed**, and it was never an SBOM decision: it is the + bug report for `/usr/local/bin/hive` failing to exec with `EPERM` under + containerd/k3s and rootless podman. Attestations force the artifact into an + OCI image *index*, which permitted an overlayfs metacopy redirect that + presented the binary as non-executable. Disabling them was the fix for a + crash-loop, not a deprioritization of supply-chain metadata. The path + forward is therefore not "re-enable the flag" — that would reintroduce the + defect — but to generate the SBOM **out-of-band** and publish it as a + release artifact, leaving the image manifest plain. Tracked in + [#6688](https://github.com/hivecommons/hive/issues/6688), which also adds a + CI assertion that the published manifest media type stays a plain image + manifest, so the constraint becomes enforced rather than comment-documented. + +- **Does any external channel exist for security-relevant project + communication?** Resolved: **no, by design.** `CONTRIBUTING.md` directs all + design and review discussion to GitHub issues and PRs "so decisions remain + public and searchable." There is no mailing list, Slack, Matrix or Discord + for project decisions. Private security traffic goes through GitHub + Security Advisories only. (The Slack/Discord/ntfy integrations in + `notifications.md` are operator-alerting *features of the software* and are + not project channels.) + +- **Does a security-specific incident-response runbook exist?** Resolved: + **yes, and it did not when this document was first written.** + [`security-response.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-response.md) + documents who responds (the Maintainer Committee, which *is* the security + team), how a report is triaged, and how disclosure is coordinated. It is + distinct from the operational `HUB_DISASTER_RECOVERY.md`. Still missing: a + post-incident-review practice and a user-notification SLA for a confirmed + compromise. + +- **Does the project intend to pursue the OpenSSF Best Practices Badge?** + Resolved: **yes.** It had not been considered before review; it is now + tracked in [#6684](https://github.com/hivecommons/hive/issues/6684), with + most passing criteria already satisfied. + +- **What is the current OpenSSF Scorecard result?** Intentionally not frozen + into this document — the workflow runs weekly and on every push to `v4`, + and a reviewer should read the live result rather than a stale number. + This is the one item from the original list that remains deliberately + unanswered here, and the reason is that quoting it would make the document + wrong on a schedule. + +- **Has any informal security review or adversarial testing occurred?** + Resolved: **no, and this is the most significant "no" in the list.** There + is no red-team exercise, no adversarial evaluation, and no measured + detection rate for `ioscan` anywhere in the repository — the search for one + returned only the phrase used in unrelated design documents. The hardening + work referenced by issue number throughout `security-threat-model.md` is + maintainer-identified and maintainer-fixed, which is not the same thing as + adversarial review. A red-team evaluation of the injection path is tracked + in [#6685](https://github.com/hivecommons/hive/issues/6685). Until it + exists, every efficacy claim about `ioscan` in this document should be read + as unvalidated by design rather than validated by silence. + +- **Will CODEOWNERS enforcement be enabled?** Resolved: the live `v4` branch + protection currently requires **no** pull-request reviews at all, and + enforcement was blocked on the fact that the project's own automation + merges green PRs. The intended resolution is scoped enforcement over + security-critical paths only, tracked in + [#6687](https://github.com/hivecommons/hive/issues/6687) along with + expanding `CODEOWNERS` from one owner to the three current maintainers. + It is a commitment with an issue behind it, not a plan to remain advisory + indefinitely. From 6e2eec2513d05c9e1401927699cdbbb65558d205 Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Fri, 11 Sep 2026 10:51:03 -0400 Subject: [PATCH 04/10] =?UTF-8?q?=F0=9F=93=96=20Sync=20Hive=20self-assessm?= =?UTF-8?q?ent:=20OpenSSF=20badge=20is=20held=20at=20passing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the canonical document from hivecommons/hive after correcting the badge status. The mirror said the badge was not yet held and being pursued; it was in fact awarded at the passing level on 2026-08-27, project 14261, four days before the TAG-Security review that asked for it. Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 64 ++++++++++--------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/projects/hive-commons/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md index 99cf34cf3..4d83765c7 100644 --- a/projects/hive-commons/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -19,7 +19,7 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > | "If I deploy this, what should I worry about?" | New section [If you deploy this, what should you worry about?](#if-you-deploy-this-what-should-you-worry-about) — the attack path stated plainly, a concern/mitigation/non-mitigation table, the three settings that determine exposure, and the worst realistic outcome. | > | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered: **no red-teaming exists.** Efficacy is now described as unmeasured and partial, with the containment credited to the network deny rules instead. Evaluation tracked in [#6685](https://github.com/hivecommons/hive/issues/6685). | > | "What is redaction for? What about base64-encoded exfiltration?" | Log scrubbing re-scoped as log hygiene, explicitly **not** an exfiltration control. Running the question against the canary path found a real gap — the egress check is substring-only — now filed as [#6686](https://github.com/hivecommons/hive/issues/6686) and recorded as a known weakness. | -> | "Get an OpenSSF passing badge." | Agreed; being pursued in [#6684](https://github.com/hivecommons/hive/issues/6684). Most passing criteria already met. | +> | "Get an OpenSSF passing badge." | **Already held, and this document was wrong to imply otherwise.** [Project 14261](https://www.bestpractices.dev/projects/14261) reached **passing** (100%) on 2026-08-27 — four days before the review — and `README.md` was displaying it throughout. The badge entry has since been corrected: 70 URLs in its criteria justifications still pointed at the pre-migration `kubestellar` org. Tracked in [#6684](https://github.com/hivecommons/hive/issues/6684). | > | "This is a huge risk. Why not mitigate it?" | Half was mitigated: the roster went from **one maintainer to three**, across three affiliations, with a documented security-response process. The unmitigated half — unenforced code ownership — is now stated as the largest remaining process risk, with scoped enforcement tracked in [#6687](https://github.com/hivecommons/hive/issues/6687). | > | "Looks like AI generated this — you should know the answer." | The "Case studies: not applicable" claim was simply **wrong**: `ADOPTERS.md` lists seven adopters, three in production, one running at ACMM L5/L6 across 43 repositories. Replaced with the real table. | > | "Go through the open questions and figure them out." | The open-questions section is gone. Every item was run down against the repository and answered in [Questions resolved since first review](#questions-resolved-since-first-review) — including two answers that are "no." | @@ -402,18 +402,15 @@ project-level compliance signals: (`scorecard.yml`, via a SHA-pinned reusable workflow in `hivecommons/infra`); results publish to the repository's code-scanning alerts. No specific score floor is gated in CI at present. -- **OpenSSF Best Practices Badge**: **not yet held — and being pursued.** At - first review of this assessment the project had not registered, and - TAG-Security's feedback was that a passing badge is achievable - low-hanging fruit whose criteria are things the project should be doing - anyway. The maintainers agree; registration and criteria completion are - tracked in [#6684](https://github.com/hivecommons/hive/issues/6684), and - this document will carry the badge ID and level once awarded rather than a - promise. The substantive prerequisites — OSI license, public VCS, private - vulnerability reporting, documented contribution process, automated test - suite in CI, static analysis, and no known unpatched vulnerabilities — are - already satisfied; what is missing is the registration and self-certification - itself. +- **OpenSSF Best Practices Badge**: **held at the passing level** — + [project 14261](https://www.bestpractices.dev/projects/14261), 100% of the + passing criteria, awarded 2026-08-27 and not lapsed since. Silver (15%) and + gold (22%) are not claimed. TAG-Security's feedback at first review was that + a passing badge is achievable low-hanging fruit whose criteria are things + the project should be doing anyway; that was correct, and the badge had in + fact already been awarded four days before the review was written. See the + "Open SSF best practices" section for why this document twice said + otherwise. - **DCO (Developer Certificate of Origin)**: enforced for human contributors via `copilot-dco.yml` and is a stated policy requirement for agent-authored commits (`git commit -s`) per `security-model.md` Layer 5 — described there @@ -710,20 +707,26 @@ repository's code-scanning alerts. This assessment deliberately does not freeze a numeric score into the text — it moves independently of this document — and a reviewer should pull the current result. -**OpenSSF Best Practices Badge: not yet held, and now being pursued.** The -first revision of this document recorded this as "not yet assessed whether -this is planned," which was an evasion; TAG-Security review called it out, -and the answer is that the project had simply not done it. It is planned, and -tracked in [#6684](https://github.com/hivecommons/hive/issues/6684). The -passing-level criteria are largely met already — OSI-approved license -(Apache-2.0), public version-controlled source, documented contribution -process, private vulnerability reporting via GitHub Security Advisories, an -automated test suite gating every PR, static analysis in CI, digest-pinned -dependencies, and no known unpatched vulnerabilities — so the outstanding -work is registration and self-certification rather than engineering. When the -badge is awarded this section will carry its ID and level; until then it -carries the issue number, because a tracked commitment is worth more to a -reviewer than a claim. +**OpenSSF Best Practices Badge: held at the passing level.** The project is +registered as [project 14261](https://www.bestpractices.dev/projects/14261) +and reached **passing** (100% of the passing criteria) on **2026-08-27**; it +has not lapsed since. The badge is displayed in `README.md` and its live +status is available from `https://www.bestpractices.dev/projects/14261/badge`. +Silver and gold are not claimed. The badge is self-certified, as the +programme intends, so its value to a reviewer is not the graphic but the +per-criterion written justifications behind it, each linking to the specific +file, workflow or policy that satisfies it — those can be checked rather than +taken on trust. + +Two earlier revisions of this section were wrong about this, in opposite +directions, and both errors are worth recording. The first said the badge was +"not yet assessed whether this is planned," which was an evasion rather than +an answer; TAG-Security review called it out. The correction then overshot by +describing the badge as not yet held and merely "being pursued" — but it had +in fact been awarded on 2026-08-27, four days before that review. In both +cases this document was written from itself rather than re-derived from +observable state, which is the same defect that left the maintainer count +stale. The badge status above is taken from the programme's public API. ### Case studies @@ -808,9 +811,10 @@ repository and answered below. Where the answer is "no," it says no. compromise. - **Does the project intend to pursue the OpenSSF Best Practices Badge?** - Resolved: **yes.** It had not been considered before review; it is now - tracked in [#6684](https://github.com/hivecommons/hive/issues/6684), with - most passing criteria already satisfied. + Resolved: **it already holds it.** [Project 14261](https://www.bestpractices.dev/projects/14261) + reached the passing level on 2026-08-27, before this question was asked. + The question survived in this document only because the document was being + written from itself rather than checked against the programme's API. - **What is the current OpenSSF Scorecard result?** Intentionally not frozen into this document — the workflow runs weekly and on every push to `v4`, From 3ec1dd754be02ad52d5aac75ed434bebb7c92e79 Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Fri, 11 Sep 2026 11:41:28 -0400 Subject: [PATCH 05/10] =?UTF-8?q?=F0=9F=93=96=20Sync=20Hive=20self-assessm?= =?UTF-8?q?ent=20from=20canonical=20v4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-mirrors the canonical document after the badge-consistency pass in hivecommons/hive. Brings across the measured ioscan red-team results and makes all badge statements agree: project 14261, passing, 100%, awarded 2026-08-27. Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 164 ++++++++++-------- 1 file changed, 88 insertions(+), 76 deletions(-) diff --git a/projects/hive-commons/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md index 4d83765c7..529195121 100644 --- a/projects/hive-commons/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -17,7 +17,7 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > | Review point | Change | > |---|---| > | "If I deploy this, what should I worry about?" | New section [If you deploy this, what should you worry about?](#if-you-deploy-this-what-should-you-worry-about) — the attack path stated plainly, a concern/mitigation/non-mitigation table, the three settings that determine exposure, and the worst realistic outcome. | -> | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered: **no red-teaming exists.** Efficacy is now described as unmeasured and partial, with the containment credited to the network deny rules instead. Evaluation tracked in [#6685](https://github.com/hivecommons/hive/issues/6685). | +> | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered, then **measured**: [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) runs a 43-payload adversarial corpus and publishes the result — **37% withheld, 63% reached the agent**, with the containment credited to the network deny rules and verified across all four ACMM modes on every test run ([#6685](https://github.com/hivecommons/hive/issues/6685)). | > | "What is redaction for? What about base64-encoded exfiltration?" | Log scrubbing re-scoped as log hygiene, explicitly **not** an exfiltration control. Running the question against the canary path found a real gap — the egress check is substring-only — now filed as [#6686](https://github.com/hivecommons/hive/issues/6686) and recorded as a known weakness. | > | "Get an OpenSSF passing badge." | **Already held, and this document was wrong to imply otherwise.** [Project 14261](https://www.bestpractices.dev/projects/14261) reached **passing** (100%) on 2026-08-27 — four days before the review — and `README.md` was displaying it throughout. The badge entry has since been corrected: 70 URLs in its criteria justifications still pointed at the pre-migration `kubestellar` org. Tracked in [#6684](https://github.com/hivecommons/hive/issues/6684). | > | "This is a huge risk. Why not mitigate it?" | Half was mitigated: the roster went from **one maintainer to three**, across three affiliations, with a documented security-response process. The unmitigated half — unenforced code ownership — is now stated as the largest remaining process risk, with scoped enforcement tracked in [#6687](https://github.com/hivecommons/hive/issues/6687). | @@ -52,7 +52,7 @@ writing) wherever a specific mechanism is asserted. | Software | [hivecommons/hive](https://github.com/hivecommons/hive) | | Security Provider | No — Hive is not itself a security product. It is an agent-orchestration platform whose core value proposition includes constraining the blast radius of the AI agents it runs; see [Overview](#overview) below. | | Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `src/bin/`, 45 scripts per [`bin/README.md`](https://github.com/hivecommons/hive/blob/v4/bin/README.md)) | -| SBOM | Not currently attached to images, for a specific and non-obvious reason rather than by oversight. `build-push-action` attaches provenance/SBOM attestations by default, and an attestation can only be carried by an OCI image *index* — which changed the published artifact from a plain manifest to `application/vnd.oci.image.index.v1+json`. That form let a `COPY --from` layer ship an overlayfs metacopy redirect for `/usr/local/bin/hive`, which containerd/k3s and rootless podman present as **non-executable**, crash-looping the image ([#3760](https://github.com/hivecommons/hive/issues/3760), now closed). `provenance: false`/`sbom: false` (`docker.yml:295,346,631,818`) is the fix for that runtime defect. The correct resolution is to generate the SBOM **out-of-band** (e.g. a syft/Trivy step publishing a release artifact) so the image manifest stays plain — tracked in [#6688](https://github.com/hivecommons/hive/issues/6688). | +| SBOM | Tagged releases publish standalone SPDX JSON SBOM release assets for `hive`, `hive-contributor`, and `hive-hub` (`hive-v-sbom.spdx.json`, `hive-contributor-v-sbom.spdx.json`, `hive-hub-v-sbom.spdx.json`) generated by Syft against the already-published GHCR images; see [releases.md](releases.md#software-bill-of-materials-sbom). These are deliberately **out-of-band** files, not in-image attestations. `docker.yml` keeps `provenance: false`/`sbom: false` (`docker.yml:295,346,631,818`) because `build-push-action` attestations force an OCI image index and reintroduced the #3760 container-runtime crash loop. The guard in `src/scripts/check-no-image-attestations.sh` asserts the image builds keep plain manifests. | | Security links | See table below | | Doc | URL | @@ -276,23 +276,43 @@ repository writes: (`ioscan.classifier.enabled`, default `false`) adds semantic plain-English-injection detection on top. **Enabled by default** (`ioscan.enabled: true` is the default per `ioscan.md:9`). - - **How well does it work? Honestly: unmeasured, and it should be read as a - partial mitigation rather than a defense.** No red-team exercise, - adversarial evaluation, or measured detection rate exists for `ioscan` — - the package has 56 unit tests across its rule, Unicode, classifier and - canary paths, but unit tests establish that known shapes are caught, not - that unknown ones are. A prospective user should assume a determined, - encoding-aware attacker defeats it. What `ioscan` reliably does is (a) - raise the cost of the *casual* injection attempt, (b) normalize away an - entire class of invisible-character and homoglyph tricks deterministically, - and (c) produce an auditable record that something was withheld. What - contains the *consequence* of a successful injection is not `ioscan` at - all: it is the hard-denied PR-create/merge relays and the mode-tiered - token scope, neither of which the model can argue with. Operators should - size their trust accordingly, and the project commits to publishing a - red-team evaluation rather than leaving efficacy asserted - ([#6685](https://github.com/hivecommons/hive/issues/6685)). + Egress canaries (`HIVE-CANARY-*`) are matched both literally and through + common transport encodings/transforms (base64, hex, URL encoding, reversed + text, case changes, and whitespace splitting) before proxy output is + allowed through. + + **How well does it work? Measured: a partial mitigation, and a narrow one** + — see [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) for the corpus, the + methodology and the full per-case table. Against 43 adversarial payloads + across six technique families, the shipped deterministic rules **withheld + 37% from the agent; 63% reached it verbatim** — 44% because no rule fired, + and a further 19% because a rule fired but the input block policy does not + block at that severity (`blockedInput` requires Critical, or Injection at + High+, so every Medium finding is recorded and the raw text is still + injected). A findings count is therefore **not** a count of attacks + stopped. + Detection is strongly uneven by family: Unicode steganography 6/8 blocked — + the one place the design beats a regex, because hidden characters are + themselves a High finding — against paraphrased instruction override 2/10 + and split-payload 0/4. The last is structural: each untrusted segment + (title, body, each comment) is scanned separately, so a phrase split across + two comments is never a single string for any rule to match. The cost side + is real too: **2 of 6 benign controls were redacted**, including an issue + *reporting* a prompt-injection bug. + A prospective user should assume a determined, encoding-aware attacker + defeats it — that is now a measurement rather than a caution. What `ioscan` + reliably does is (a) raise the cost of the *casual* injection attempt, (b) + normalize away an entire class of invisible-character and homoglyph tricks + deterministically, and (c) produce an auditable record that something was + withheld. What contains the *consequence* of a successful injection is not + `ioscan` at all: it is the hard-denied PR-create/merge relays and the + mode-tiered token scope, neither of which the model can argue with — and + that containment is now verified across all four ACMM modes by + `TestRedTeamContainmentHoldsForEveryMode` on every test run rather than + asserted here. Operators should size their trust accordingly. The + evaluation's own limits are stated in it: the optional LLM classifier is + default-off and its contribution remains unmeasured, and the corpus covers + the input path only. **Exfiltration detection (`ioscan.canaries`, default off).** A per-agent `HIVE-CANARY-<48 hex>` token is planted in the agent's prompt, and the @@ -402,15 +422,20 @@ project-level compliance signals: (`scorecard.yml`, via a SHA-pinned reusable workflow in `hivecommons/infra`); results publish to the repository's code-scanning alerts. No specific score floor is gated in CI at present. -- **OpenSSF Best Practices Badge**: **held at the passing level** — - [project 14261](https://www.bestpractices.dev/projects/14261), 100% of the - passing criteria, awarded 2026-08-27 and not lapsed since. Silver (15%) and - gold (22%) are not claimed. TAG-Security's feedback at first review was that - a passing badge is achievable low-hanging fruit whose criteria are things - the project should be doing anyway; that was correct, and the badge had in - fact already been awarded four days before the review was written. See the - "Open SSF best practices" section for why this document twice said - otherwise. +- **OpenSSF Best Practices Badge**: **held at the `passing` level** — project + [14261](https://www.bestpractices.dev/projects/14261), achieved 2026-08-27, + 100% of the passing criteria (all 67 Met or Not-Applicable). This is a + maintainer **self**-certification against published criteria, publicly + auditable per-criterion — not a third-party audit, and so not a + counter-example to the "no formal security certification" sentence above. + The badge is displayed in `README.md` and its state is live, so the image + tracks the project's current level rather than the level at the time of this + writing; no level beyond `passing` is claimed here, for the same reason the + Scorecard number above is not frozen into this document. TAG-Security's + feedback was that a passing badge is achievable low-hanging fruit whose + criteria are things the project should be doing anyway; the maintainers + agreed, and [#6684](https://github.com/hivecommons/hive/issues/6684) tracked + it to completion. - **DCO (Developer Certificate of Origin)**: enforced for human contributors via `copilot-dco.yml` and is a stated policy requirement for agent-authored commits (`git commit -s`) per `security-model.md` Layer 5 — described there @@ -418,10 +443,12 @@ project-level compliance signals: guarantee,"* i.e. Hive asks agents to sign off but the hard gate is a repo-side branch-protection setting the operator must also enable. - **License**: Apache License 2.0 (`LICENSE`), OSI-approved, CNCF-preferred. -- **No formal SBOM** is currently attached to release artifacts — for the - container-runtime reason explained under [Metadata](#metadata), with the - out-of-band path recorded in - [Questions resolved since first review](#questions-resolved-since-first-review). +- **SBOMs**: tagged releases attach standalone SPDX JSON SBOM files for each + published image (`hive`, `hive-contributor`, `hive-hub`) as GitHub Release + assets, generated by Syft against the already-published GHCR images. They + are intentionally not attached to image manifests; the container-runtime + reason is explained under [Metadata](#metadata) and in + [releases.md](releases.md#software-bill-of-materials-sbom). ## Secure development practices @@ -450,7 +477,9 @@ project-level compliance signals: `gh`, goose, `su-exec`). - **No SBOM/provenance attestation** is attached to built images — explicitly disabled (`sbom: false`, citing issue #3760) rather than merely absent by - omission. Not yet assessed whether #3760 documents a planned reintroduction. + omission. Release SBOMs are generated out-of-band as standalone SPDX JSON + files and attached to the GitHub Release, so the published image manifests + stay plain. - **Maintainer roster**: `OWNERS` lists **three** approvers/reviewers — Andy Anderson (@clubanderson, IBM), James Reilly (@hanthor, Universal Blue) and Doug Baggett (@Danathar, independent). This is a change since @@ -461,22 +490,14 @@ project-level compliance signals: Maintainer Committee table in upstream `GOVERNANCE-HIVE.md`, and the file says so explicitly, calling drift "a governance drift bug, not a housekeeping detail." -- **CODEOWNERS**: `.github/CODEOWNERS` covers security-sensitive paths - (Dockerfiles, workflows, deploy manifests, launch scripts, key/cookie - code) but is **advisory only** — "Require review from Code Owners" is not - enabled in `v4` branch protection (verified against the live branch - protection API: no required pull-request reviews are configured; one - required status check is). The reason is stated in the file's own header: - the repository's automation merges green PRs, and enforcement would block - it. Two honest consequences follow. First, every path in that file - currently resolves to a single owner (`@clubanderson`) even though three - maintainers now exist — a lag between the governance change and the - ownership file, being corrected. Second, and more important: a change to - the proxy deny-rule table or the SUID contract script can merge on green - CI without a human security reviewer. That is a real gap between what - CODEOWNERS implies and what branch protection enforces, and it is the - project's largest remaining process risk — see - [Known weaknesses](#three-most-significant-known-weaknesses). +- **CODEOWNERS**: `.github/CODEOWNERS` is scoped to the security-sensitive + paths whose changes can directly alter security boundaries (proxy policy, + Dockerfiles, workflow definitions, deploy manifests, SUID contract checks, + and key/cookie/session handling), and every entry names all three current + maintainers (`@clubanderson`, `@hanthor`, `@Danathar`). The remaining + repo-side step is enabling "Require review from Code Owners" in `v4` branch + protection; until that is enabled, CODEOWNERS is still advisory rather than + enforced — see [Known weaknesses](#three-most-significant-known-weaknesses). ### Communication channels @@ -621,29 +642,22 @@ because a self-assessment that only lists strengths is not credible: availability. **What remains unmitigated is the enforcement gap, and it is real.** - `.github/CODEOWNERS` covers the security-sensitive paths — Dockerfiles, - CI workflows, deploy manifests, launch scripts, key/cookie handling — but - "Require review from Code Owners" is **not enabled** in `v4` branch - protection, which the live API confirms: no required pull-request reviews - are configured at all. Every path in that file also still resolves to a - single owner, lagging the governance change. The net effect is that a - change to the MITM proxy's deny-rule table — the control this document - credits as the thing an attacker cannot argue with — can merge on green - CI with no human security reviewer. + `.github/CODEOWNERS` now covers only the security-sensitive paths — + Dockerfiles, CI workflows, deploy manifests, SUID contract checks, proxy + policy, and key/cookie/session handling — and lists all three current + maintainers on every entry. But "Require review from Code Owners" still + has to be enabled in `v4` branch protection after the scoped file lands. + Until then, a change to the MITM proxy's deny-rule table — the control + this document credits as the thing an attacker cannot argue with — can + merge on green CI with no human security reviewer. **Why it has not simply been turned on.** This is the honest trade at the center of the project: Hive is substantially self-hosting, and its own - agent fleet merges green PRs. Enabling required code-owner review would - halt that automation repository-wide, which is why `CODEOWNERS` itself - documents the choice in its header rather than leaving it implicit. That - is an explanation, not a justification, and the maintainers do not offer - it as one. The defensible resolution is not "all or nothing" but a - **scoped** enforcement rule covering only the security-critical paths - (proxy rules, SUID contract, workflows, deploy manifests, key handling), - leaving ordinary code paths on the automated merge path. That is tracked - in [#6687](https://github.com/hivecommons/hive/issues/6687), together - with updating `CODEOWNERS` to list all three maintainers so enforcement - is survivable when it lands. + agent fleet merges green PRs. Enabling required code-owner review with + broad coverage would halt that automation repository-wide. The defensible + resolution is not "all or nothing" but the scoped ownership file above, + leaving ordinary code paths on the automated merge path while making the + human-review boundary enforceable for security-critical changes. Until that ships, an evaluator should treat "the deny-rule table is enforced in code" as true and "the deny-rule table is protected from @@ -784,13 +798,11 @@ repository and answered below. Where the answer is "no," it says no. containerd/k3s and rootless podman. Attestations force the artifact into an OCI image *index*, which permitted an overlayfs metacopy redirect that presented the binary as non-executable. Disabling them was the fix for a - crash-loop, not a deprioritization of supply-chain metadata. The path - forward is therefore not "re-enable the flag" — that would reintroduce the - defect — but to generate the SBOM **out-of-band** and publish it as a - release artifact, leaving the image manifest plain. Tracked in - [#6688](https://github.com/hivecommons/hive/issues/6688), which also adds a - CI assertion that the published manifest media type stays a plain image - manifest, so the constraint becomes enforced rather than comment-documented. + crash-loop, not a deprioritization of supply-chain metadata. The release + workflow now generates SBOMs **out-of-band** and publishes them as GitHub + Release assets, leaving the image manifest plain; the + `check-no-image-attestations.sh` guard keeps future `docker.yml` changes + from silently reattaching in-image attestations. - **Does any external channel exist for security-relevant project communication?** Resolved: **no, by design.** `CONTRIBUTING.md` directs all From 52a8bf2ac1debb6e95e2a656393972c0ca536262 Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Fri, 11 Sep 2026 12:39:50 -0400 Subject: [PATCH 06/10] docs(hive): re-sync self-assessment mirror from canonical Canonical hivecommons/hive v4 now reports 42% of attack payloads withheld and 58% reaching the agent (Unicode family 8/8) after #6714 closed the fullwidth-capital and soft-hyphen gaps, and records the canary egress check as encoding-aware after #6686 was fixed. This mirror still carried the superseded 37%/63%, 6/8 and substring-only text. Also rewrites two relative releases.md links that resolve nowhere in this repository. Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 77 +++++++++++-------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/projects/hive-commons/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md index 529195121..7ddac9271 100644 --- a/projects/hive-commons/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -17,8 +17,8 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > | Review point | Change | > |---|---| > | "If I deploy this, what should I worry about?" | New section [If you deploy this, what should you worry about?](#if-you-deploy-this-what-should-you-worry-about) — the attack path stated plainly, a concern/mitigation/non-mitigation table, the three settings that determine exposure, and the worst realistic outcome. | -> | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered, then **measured**: [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) runs a 43-payload adversarial corpus and publishes the result — **37% withheld, 63% reached the agent**, with the containment credited to the network deny rules and verified across all four ACMM modes on every test run ([#6685](https://github.com/hivecommons/hive/issues/6685)). | -> | "What is redaction for? What about base64-encoded exfiltration?" | Log scrubbing re-scoped as log hygiene, explicitly **not** an exfiltration control. Running the question against the canary path found a real gap — the egress check is substring-only — now filed as [#6686](https://github.com/hivecommons/hive/issues/6686) and recorded as a known weakness. | +> | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered, then **measured**: [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) runs a 43-payload adversarial corpus and publishes the result — **42% withheld, 58% reached the agent**, with the containment credited to the network deny rules and verified across all four ACMM modes on every test run ([#6685](https://github.com/hivecommons/hive/issues/6685)). | +> | "What is redaction for? What about base64-encoded exfiltration?" | Log scrubbing re-scoped as log hygiene, explicitly **not** an exfiltration control. Running the question against the canary path found a real gap — the egress check was substring-only — filed as [#6686](https://github.com/hivecommons/hive/issues/6686) and **since fixed**: the proxy now decodes and normalizes outbound bodies before matching canaries. | > | "Get an OpenSSF passing badge." | **Already held, and this document was wrong to imply otherwise.** [Project 14261](https://www.bestpractices.dev/projects/14261) reached **passing** (100%) on 2026-08-27 — four days before the review — and `README.md` was displaying it throughout. The badge entry has since been corrected: 70 URLs in its criteria justifications still pointed at the pre-migration `kubestellar` org. Tracked in [#6684](https://github.com/hivecommons/hive/issues/6684). | > | "This is a huge risk. Why not mitigate it?" | Half was mitigated: the roster went from **one maintainer to three**, across three affiliations, with a documented security-response process. The unmitigated half — unenforced code ownership — is now stated as the largest remaining process risk, with scoped enforcement tracked in [#6687](https://github.com/hivecommons/hive/issues/6687). | > | "Looks like AI generated this — you should know the answer." | The "Case studies: not applicable" claim was simply **wrong**: `ADOPTERS.md` lists seven adopters, three in production, one running at ACMM L5/L6 across 43 repositories. Replaced with the real table. | @@ -52,7 +52,7 @@ writing) wherever a specific mechanism is asserted. | Software | [hivecommons/hive](https://github.com/hivecommons/hive) | | Security Provider | No — Hive is not itself a security product. It is an agent-orchestration platform whose core value proposition includes constraining the blast radius of the AI agents it runs; see [Overview](#overview) below. | | Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `src/bin/`, 45 scripts per [`bin/README.md`](https://github.com/hivecommons/hive/blob/v4/bin/README.md)) | -| SBOM | Tagged releases publish standalone SPDX JSON SBOM release assets for `hive`, `hive-contributor`, and `hive-hub` (`hive-v-sbom.spdx.json`, `hive-contributor-v-sbom.spdx.json`, `hive-hub-v-sbom.spdx.json`) generated by Syft against the already-published GHCR images; see [releases.md](releases.md#software-bill-of-materials-sbom). These are deliberately **out-of-band** files, not in-image attestations. `docker.yml` keeps `provenance: false`/`sbom: false` (`docker.yml:295,346,631,818`) because `build-push-action` attestations force an OCI image index and reintroduced the #3760 container-runtime crash loop. The guard in `src/scripts/check-no-image-attestations.sh` asserts the image builds keep plain manifests. | +| SBOM | Tagged releases publish standalone SPDX JSON SBOM release assets for `hive`, `hive-contributor`, and `hive-hub` (`hive-v-sbom.spdx.json`, `hive-contributor-v-sbom.spdx.json`, `hive-hub-v-sbom.spdx.json`) generated by Syft against the already-published GHCR images; see [releases.md](https://github.com/hivecommons/hive/blob/v4/src/docs/releases.md#software-bill-of-materials-sbom). These are deliberately **out-of-band** files, not in-image attestations. `docker.yml` keeps `provenance: false`/`sbom: false` (`docker.yml:295,346,631,818`) because `build-push-action` attestations force an OCI image index and reintroduced the #3760 container-runtime crash loop. The guard in `src/scripts/check-no-image-attestations.sh` asserts the image builds keep plain manifests. | | Security links | See table below | | Doc | URL | @@ -193,7 +193,7 @@ control removes it; the controls bound the consequences. |---|---|---| | Attacker text talks an agent into **merging** malicious code | `PUT /pulls/{n}/merge` is **hard-denied for every ACMM mode** at the proxy (`rules.go:215-226`), as is the GraphQL merge mutation. The agent never holds a credential path to merge; `hive-merge` runs as Hive with a SHA-pinned eligibility binding. | `ioscan`. A sufficiently clever prompt defeats a scanner; it does not defeat a rule table the model never sees. | | Attacker text talks an agent into **opening a PR** with a backdoor | `POST /pulls` is likewise hard-denied for every mode. PR creation goes through `hive-open-pr` as the App bot, attribution-stamped and audit-logged. | Nothing prevents the *content* of a legitimately-created PR from being attacker-influenced. Review it like any other PR. | -| Attacker exfiltrates your **secrets** via the agent | Mode-tiered tokens mean low-tier agents never hold code-write credentials. Optional `ioscan` canaries detect prompt contents echoed into outbound GitHub writes at the proxy. | Canaries are **default-off** and substring-matched — see the [encoding gap](#three-most-significant-known-weaknesses). Non-GitHub egress is tunneled without inspection. | +| Attacker exfiltrates your **secrets** via the agent | Mode-tiered tokens mean low-tier agents never hold code-write credentials. Optional `ioscan` canaries detect prompt contents echoed into outbound GitHub writes at the proxy, including base64/hex/URL-encoded, reversed and split spellings of the token. | Canaries are **default-off**, and their transform list is finite — an encoding it does not model still passes. `git-receive-pack` bodies are unscannable, and non-GitHub egress is tunneled without inspection. | | Agent burns your **inference budget** in a loop | Seven-day rolling token budget suppresses kicks on exhaustion. | Nothing caps the *rate* within budget. | | Compromised agent attacks **other agents** on the same spoke | Per-UID separation stops tmux attach and token-file reads. | Shared container/kernel. See weakness #2. | @@ -277,21 +277,26 @@ repository writes: plain-English-injection detection on top. **Enabled by default** (`ioscan.enabled: true` is the default per `ioscan.md:9`). Egress canaries (`HIVE-CANARY-*`) are matched both literally and through - common transport encodings/transforms (base64, hex, URL encoding, reversed - text, case changes, and whitespace splitting) before proxy output is - allowed through. + the transport encodings a body can carry: base64 (standard and URL-safe, + padded or not, line-wrapped, and one level of nesting), hex (either case, + with per-byte separators or `\x`/`0x` escapes), percent-encoding, reversed + text, case changes, homoglyph and zero-width substitution, and separator + splitting — plus any intact 16-hex-character window of a token's random + half, so a token broken across a body still trips. Decoding recurs a + bounded number of passes with a byte budget, because the body being + decoded is attacker-influenced. **How well does it work? Measured: a partial mitigation, and a narrow one** — see [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) for the corpus, the methodology and the full per-case table. Against 43 adversarial payloads across six technique families, the shipped deterministic rules **withheld - 37% from the agent; 63% reached it verbatim** — 44% because no rule fired, + 42% from the agent; 58% reached it verbatim** — 40% because no rule fired, and a further 19% because a rule fired but the input block policy does not block at that severity (`blockedInput` requires Critical, or Injection at High+, so every Medium finding is recorded and the raw text is still injected). A findings count is therefore **not** a count of attacks stopped. - Detection is strongly uneven by family: Unicode steganography 6/8 blocked — + Detection is strongly uneven by family: Unicode steganography 8/8 blocked — the one place the design beats a regex, because hidden characters are themselves a High finding — against paraphrased instruction override 2/10 and split-payload 0/4. The last is structural: each untrusted segment @@ -319,11 +324,19 @@ repository writes: egress proxy scans outbound GitHub request bodies for it (`github_proxy.go:1179-1205`): a hit is positive evidence that prompt contents reached a write, and is audit-logged and — with - `fail_mode: closed` — blocked. Two limits are stated rather than implied: - the match is a literal substring test (`canary.go`, `strings.Contains`), - so **an encoded canary is not detected**, and `git-receive-pack` bodies - are opaque to it, so a push is only stopped when fail-closed is set. Both - are tracked in [Known weaknesses](#three-most-significant-known-weaknesses). + `fail_mode: closed` — blocked. The match is no longer a literal substring + test: `CanaryRegistry.Scan` normalizes the body and decodes what it finds + before matching, so the encodings listed above are caught + ([#6686](https://github.com/hivecommons/hive/issues/6686)). Two limits + remain, and are stated rather than implied: the transform list is + **finite and enumerated**, so an encoding it does not model — a cipher, a + custom alphabet, a canary spliced into the middle of an unrelated base64 + run, or a token cut into pieces shorter than a 16-character window and + spread across separate requests — still passes; and `git-receive-pack` + bodies are opaque to the scan, so a push is only stopped when fail-closed + is set (tracked in + [Known weaknesses](#three-most-significant-known-weaknesses)). A canary + hit remains positive evidence; a miss has never been proof of absence. 3. **Per-agent scoped GitHub App tokens and mode-tiered credential issuance** (per `security-model.md` Layer 5). Advisory-mode agents receive @@ -388,11 +401,13 @@ repository writes: containment. The controls that do bear on that attack are elsewhere and are also imperfect: mode-tiered token scoping means a low-tier agent has no code-write credential to leak in the first place; `ioscan`'s canary check - at the proxy catches prompt contents reaching an outbound GitHub write - (but, as noted above, only as a literal substring — the base64 case defeats - it too, and closing that gap is tracked in - [#6686](https://github.com/hivecommons/hive/issues/6686)); and non-GitHub - destinations are tunneled without inspection at all. An operator who needs + at the proxy catches prompt contents reaching an outbound GitHub write, + and — unlike log scrubbing — it does decode base64, hex and percent-encoded + bodies and normalize away splitting before matching + ([#6686](https://github.com/hivecommons/hive/issues/6686)), though only for + the transforms it enumerates and only for the canary token rather than for + credentials at large; and non-GitHub destinations are tunneled without + inspection at all. An operator who needs a hard guarantee against credential egress should not rely on any of these and should scope the credentials themselves. - **Ed25519-only session/SSO verification** (`security-model.md` "Sessions @@ -448,7 +463,7 @@ project-level compliance signals: assets, generated by Syft against the already-published GHCR images. They are intentionally not attached to image manifests; the container-runtime reason is explained under [Metadata](#metadata) and in - [releases.md](releases.md#software-bill-of-materials-sbom). + [releases.md](https://github.com/hivecommons/hive/blob/v4/src/docs/releases.md#software-bill-of-materials-sbom). ## Secure development practices @@ -677,20 +692,16 @@ can be much longer. This is a real, if secondary, forensic-capability limit on the accountability mechanism this document otherwise credits as a strength. -Two further narrow gaps, surfaced because they were found while responding to +One further narrow gap, surfaced because it was found while responding to TAG-Security review and it would be poor practice to let review-driven -discoveries go unrecorded: - -- **The canary egress check is not encoding-aware.** `CanaryRegistry.Scan` - tests with `strings.Contains`, so an agent induced to emit its canary - base64-encoded, hex-encoded, reversed, or split across a body passes the - proxy check unflagged — even though `ioscan`'s *input* path does decode - base64 and normalize Unicode before scanning. The asymmetry is an - oversight rather than a decision, and is tracked in - [#6686](https://github.com/hivecommons/hive/issues/6686). Note the control - degrades to "no worse than not having it," not to a false assurance, since - a canary hit is positive evidence and a miss was never treated as proof of - absence. +discoveries go unrecorded. (A second one recorded here in revision 2 — that +the canary egress check matched literal substrings only, so a base64-encoded +canary passed unflagged — has since been closed: `CanaryRegistry.Scan` +decodes and normalizes before matching, and the residual limit is now the +finite transform list described under +[Critical security components](#critical-security-components), not the +absence of decoding.) + - **`git-receive-pack` bodies are opaque to canary scanning.** A `git push` is pack-encoded, so the proxy cannot inspect it for leaked markers; with `fail_mode: closed` the push is refused outright, and otherwise it From 9c772add38d4c8ae140be6c0837aa8f3375864da Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Tue, 15 Sep 2026 14:06:47 -0400 Subject: [PATCH 07/10] docs(hive): sync self-assessment rev 3 from canonical (second TAG-Security review) Mirrors hivecommons/hive#7088. Adds credential storage and blast-radius tables, hub<->spoke interface threat table (#7082), contributor relay authentication, corrected fail_mode framing (#7083), condensed red-team summary, image-composition tradeoff, and a readability pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 220 ++++++++++++++---- 1 file changed, 170 insertions(+), 50 deletions(-) diff --git a/projects/hive-commons/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md index 7ddac9271..78717f677 100644 --- a/projects/hive-commons/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -26,6 +26,20 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > > Net effect: five issues filed ([#6684](https://github.com/hivecommons/hive/issues/6684), [#6685](https://github.com/hivecommons/hive/issues/6685), [#6686](https://github.com/hivecommons/hive/issues/6686), [#6687](https://github.com/hivecommons/hive/issues/6687), [#6688](https://github.com/hivecommons/hive/issues/6688)), one previously-undetected defect found, and several claims corrected against the repository rather than restated. +> **Revision 3 — second TAG-Security review (same PR).** Six further +> questions, mostly about the parts of the trust model the document had +> described by control rather than by consequence: +> +> | Review point | Change | +> |---|---| +> | "Where are GitHub tokens and inference keys stored? What is compromised if an operator is? What threatens install/update?" | New [Credentials: where they live and what falls with them](#credentials-where-they-live-and-what-falls-with-them) — a storage table, a blast-radius table per actor, and the supply-chain facts for install/upgrade. | +> | "How does hive authenticate a contributor/relay?" | New [Contributor relay authentication](#contributor-relay-authentication). | +> | "Were threats identified on the hub↔spoke interface?" | New [Hub ↔ spoke interface](#hub--spoke-interface) with a threat table. One finding: hub→spoke config pushes rely on TLS alone and are not independently signed — filed as [#7082](https://github.com/hivecommons/hive/issues/7082). | +> | "What would `fail_mode: closed` and canaries-on by default cost? Are they partial mitigations? Plans?" | The document's own framing was wrong: `open` **redacts** and continues, it does not pass injection through. Corrected in three places. Defaults plan tracked in [#7083](https://github.com/hivecommons/hive/issues/7083). | +> | "The red-team section duplicates `ioscan-red-team.md`." | Cut to a summary that links out. | +> | "The image bundles every CLI backend — by design?" | Yes; stated as a tradeoff with its cost and the roadmap under [Security relevant components](#security-relevant-components). | +> | "Some sections are dense." | Long paragraphs in the critical-components and weaknesses sections broken up or replaced with tables; a stale "no adversarial testing has occurred" answer in the appendix corrected. | + It complements, and deliberately does not duplicate, three existing security documents in the Hive repository: @@ -107,7 +121,9 @@ obey. that reaches agent prompts. - **Contributors via ClankeR relay** — external contributors who donate compute by running an agent against a hive's queue over a relay protocol - (see [contributor-relay.md](https://github.com/hivecommons/hive/blob/v4/src/docs/contributor-relay.md)). + (see [contributor-relay.md](https://github.com/hivecommons/hive/blob/v4/src/docs/contributor-relay.md) and + [Contributor relay authentication](#contributor-relay-authentication) + below). Their machines are outside Hive's trust boundary. - **Hub operators / SaaS platform operators** — run the central hub that coordinates registered spokes and, for hosted spokes, provisions infrastructure and injects GitHub App credentials. @@ -138,6 +154,98 @@ obey. central hub; the hub can push configuration (including GitHub App credentials for hub-provisioned hives) back to a spoke. +### Credentials: where they live and what falls with them + +The Actors list names the credentials; this section says where each one is +stored and what an attacker gets by compromising each actor. Paths are for the +hub-provisioned ("hosted") deployment, which is the highest-exposure shape; +self-hosted spokes store the same material wherever the operator's +`hive.yaml` points. + +| Credential | Hosted spoke | Hub | Self-hosted spoke | +|---|---|---|---| +| GitHub App private key | Projected from the `hive-secrets` Kubernetes Secret as a whole-volume mount, mode **0440** with the pod `fsGroup`. A spoke receives **only its own** App key — an earlier design rendered every fleet key into every spoke and was removed (audit finding N1, CWE-200; `saas_provision.go`, "AdditionalAppKeys"). | One **0600** file per cluster, keyed by cluster ID; never rendered into any spoke manifest. | `github.key_file` in `hive.yaml`, or env; operator-managed. | +| Inference / model API keys | Same `hive-secrets` Secret. Keys entered in the dashboard are written back through a scoped `hive-secrets-writer` Role, not by the hive process's own identity. | Not held for spokes. | `hive.yaml` / env. | +| Hub master secret (`HIVE_HUB_SECRET`) | **Never leaves the hub.** The spoke receives only domain-separated sub-keys derived from it (`src/pkg/keyderive`): a per-hive heartbeat bearer, a session-verification key, and the SSO **public** key. | Hub only. | n/a | +| Dashboard auth token | Generated per hive at provision time; in `hive-secrets` and `hive.yaml`. | n/a | `hive.yaml`. | +| Per-agent GitHub tokens | Minted from the App key inside the spoke, mode-tiered (Layer 5), written to per-UID token files the other agents cannot read. | n/a | Same. | + +**Blast radius by compromised actor** + +| Compromised | Attacker obtains | Attacker does *not* obtain | +|---|---|---| +| A **spoke** (operator, pod, or an agent that escapes its UID) | That spoke's App installation scope — the repositories it governs — its dashboard token, and its inference keys. | Other tenants' App keys; the hub master; the ability to mint an admin session or an SSO-as-any-owner token (those signing keys are hub-only; the spoke holds only the public half). | +| A **contributor relay** | A 55-minute scoped GitHub token for the task it was assigned, re-minted while the task is live. | Any hive-side credential; merge capability (relay output enters at the PR-review gate like any external PR). | +| The **hub** | Everything: the hub provisions spokes and pushes configuration and App credentials to them over the heartbeat lane. | — | + +The last row is the important asymmetry, and the reason the [hub ↔ spoke +interface](#hub--spoke-interface) gets its own section: **the hub is the +highest-value asset in the system**, and a hub compromise is fleet-wide. + +**Install and upgrade.** The threats an operator faces while installing or +updating are supply-chain threats, and the current facts are: + +- Base images are pinned by digest (`src/Dockerfile:8,64,92`: `golang@sha256:…`, + `node@sha256:…`). CLI backends are pinned by version; where upstream + publishes a checksum the build verifies a per-arch SHA-256 and hard-fails on + mismatch (Goose, muse). All npm CLI installs run with `--ignore-scripts`. +- Upgrades are **pull-based**. A spoke learns its target from the hub and + patches its *own* Deployment through a namespaced ServiceAccount whose Role + is `get`/`patch` on that one Deployment (`src/pkg/hub/spoke/self_upgrade.go`). + The hub does not need cluster credentials to a spoke's cluster to upgrade it, + and a spoke cannot reach anything but itself. +- Gap: SBOM/provenance attestations are **off** on image builds (#3760, see + Metadata). The supply chain is pinned but not attestable end-to-end; SBOMs + ship out-of-band as release assets. + +### Hub ↔ spoke interface + +Registered spokes heartbeat to a hub; the hub answers with configuration and, +for hosted spokes, credentials. The two directions are not equally protected. + +| Direction | What is sent | How it is authenticated | +|---|---|---| +| **Spoke → hub** (heartbeat) | Operational telemetry: agent states, queue depth, version, health. **Never credentials.** | A **per-hive derived bearer** (`keyderive.PerHiveKey`, bound to trust domain and hive ID), verified against every live master generation so the master can rotate without a flag day (`src/pkg/hub/hub_keys.go`, `verifyHeartbeatBearerAcrossGenerations`). The fleet-wide shared bearer lane of earlier releases is **deleted**. | +| **Hub → spoke** (heartbeat response) | Configuration deltas; for hosted spokes, the spoke's GitHub App credentials and authorized-user list. | **TLS to the spoke's configured hub URL — and nothing else.** The response body is not signed and is not bound to a hive ID or sequence number. | +| **Hub-minted tokens** (SSO, delegation, session cookies) | Identity assertions the spoke must verify. | **Ed25519**; the spoke holds only the public key (`HIVE_SSO_PUBLIC_KEY`, `src/pkg/delegation/token.go`). A spoke without a key fails closed (503). | + +Threats identified on this interface: + +| Threat | Status | +|---|---| +| **Hub compromise → fleet-wide credential and config push** | Real and unmitigated by design of the lane; bounded only by hub hardening and by each spoke holding its own App key alone. Stated as the system's highest-value target. | +| **Spoke impersonation** to the hub | Bounded. One leaked bearer authenticates one hive; the hub will not accept it for another hive ID, and rotation retires it within the dual-generation window. | +| **Replay, rollback, or mis-delivery of a pushed configuration** (a TLS-terminating middlebox, a misconfigured `HIVE_HUB_URL`, a captured response replayed to a different hive) | **Open.** Filed as [#7082](https://github.com/hivecommons/hive/issues/7082): sign the response with the hub's existing Ed25519 key and bind it to `hive_id` plus a monotonic sequence, rolling out log-only before enforcing. | +| **Telemetry disclosure** | Low. Heartbeats carry no secrets; the hub-side view is admin-gated. | + +### Contributor relay authentication + +The ClankeR relay lets a contributor lend their own AI CLI subscription to a +hive from their own machine. That machine is outside the trust boundary, so +the design authenticates the *contributor* and scopes what the relay can do +rather than trusting the relay's output: + +- **Registration.** A contributor registers once against a GitHub identity. + The hive issues a registration token and stores **only its SHA-256 hash** + in the contributor profile (`api_contribute.go`, `sha256Hex(token)`); the + profile file is 0600 because it also carries PII. The plaintext is shown + once and lives in the contributor's `~/.config/hive/contributor.env`. +- **Connection.** The relay presents the token as a bearer on + `wss:///api/contribute/ws`; the hive hashes it and compares in + constant time (`contributorProfileFromRegistrationToken`). +- **Authorization.** Every contributor has a **trust tier** with per-tier + rate limits and model admission + ([contributor-trust-and-roles.md](https://github.com/hivecommons/hive/blob/v4/src/docs/contributor-trust-and-roles.md)). +- **Per-task credential.** The hub mints a **55-minute** GitHub token scoped + to the assigned task and re-mints it while the task is live; the lease is + fenced to that contributor identity and abandoned after 30 minutes without + progress or a 4-hour backstop. + +Weaknesses, stated: the registration token is a long-lived bearer with no +expiry or rotation today; and a malicious relay can submit a malicious pull +request — which is why relay output enters at exactly the same review gate as +any external contributor's PR and is never merge-eligible on its own. + ### Goals - Constrain what an LLM-driven agent process can do to a real source @@ -208,9 +316,16 @@ control removes it; the controls bound the consequences. trusted collaborators collapses most of the untrusted-input surface. The threat model above is substantially a *public-repository* threat model. 3. **Whether you enabled `ioscan.canaries` and `fail_mode: closed`.** Both - default to the permissive setting. The defaults favor availability; a - security-sensitive deployment should change them and accept that a - scanner outage then becomes a scheduling outage. + default off. Be precise about what the defaults do: `fail_mode: open` + **redacts** a Critical finding and continues the kick — it does not pass + the injection through; `closed` blocks the kick and writes an + `ioscan_fail_closed` audit entry. The cost of `closed` is that every + Critical false positive becomes a stalled queue item needing an operator. + Canaries add a per-kick marker and an egress scan. Both are partial + mitigations (see below); a security-sensitive deployment should enable + both. The project's plan is to make canaries the default everywhere and + `closed` the default at ACMM ≥ L5, where agents can merge + ([#7083](https://github.com/hivecommons/hive/issues/7083)). **What we would tell a new operator.** Start at L1–L3 on a repository you would not mind an agent filing a bad issue on. Read the attribution trailers @@ -286,38 +401,28 @@ repository writes: bounded number of passes with a byte budget, because the body being decoded is attacker-influenced. - **How well does it work? Measured: a partial mitigation, and a narrow one** - — see [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) for the corpus, the - methodology and the full per-case table. Against 43 adversarial payloads - across six technique families, the shipped deterministic rules **withheld - 42% from the agent; 58% reached it verbatim** — 40% because no rule fired, - and a further 19% because a rule fired but the input block policy does not - block at that severity (`blockedInput` requires Critical, or Injection at - High+, so every Medium finding is recorded and the raw text is still - injected). A findings count is therefore **not** a count of attacks - stopped. - Detection is strongly uneven by family: Unicode steganography 8/8 blocked — - the one place the design beats a regex, because hidden characters are - themselves a High finding — against paraphrased instruction override 2/10 - and split-payload 0/4. The last is structural: each untrusted segment - (title, body, each comment) is scanned separately, so a phrase split across - two comments is never a single string for any rule to match. The cost side - is real too: **2 of 6 benign controls were redacted**, including an issue - *reporting* a prompt-injection bug. - A prospective user should assume a determined, encoding-aware attacker - defeats it — that is now a measurement rather than a caution. What `ioscan` - reliably does is (a) raise the cost of the *casual* injection attempt, (b) - normalize away an entire class of invisible-character and homoglyph tricks - deterministically, and (c) produce an auditable record that something was - withheld. What contains the *consequence* of a successful injection is not - `ioscan` at all: it is the hard-denied PR-create/merge relays and the - mode-tiered token scope, neither of which the model can argue with — and - that containment is now verified across all four ACMM modes by - `TestRedTeamContainmentHoldsForEveryMode` on every test run rather than - asserted here. Operators should size their trust accordingly. The - evaluation's own limits are stated in it: the optional LLM classifier is - default-off and its contribution remains unmeasured, and the corpus covers - the input path only. + **How well does it work? Measured: a partial, uneven mitigation.** + [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) runs a 43-payload adversarial + corpus across six technique families against the shipped rules and + publishes the per-case table. The headline: + + | | | + |---|---| + | Withheld from the agent | **42%** | + | Reached the agent verbatim | **58%** — 40% no rule fired; 19% a rule fired below the blocking severity | + | Strongest family | Unicode steganography, 8/8 blocked | + | Weakest families | Paraphrased instruction override 2/10; split-payload 0/4 (segments are scanned separately) | + | False positives | 2 of 6 benign controls redacted | + + Read it as: `ioscan` raises the cost of a *casual* injection, removes an + entire class of invisible-character tricks deterministically, and leaves + an audit record — and a determined, encoding-aware attacker gets through. + What contains the *consequence* is not `ioscan`: it is the hard-denied + PR-create/merge relays and mode-tiered token scope, which the model cannot + argue with, and which `TestRedTeamContainmentHoldsForEveryMode` verifies + across all four ACMM modes on every test run. The optional LLM classifier + is default-off and its contribution is unmeasured; the corpus covers the + input path only. **Exfiltration detection (`ioscan.canaries`, default off).** A per-agent `HIVE-CANARY-<48 hex>` token is planted in the agent's prompt, and the @@ -410,6 +515,19 @@ repository writes: inspection at all. An operator who needs a hard guarantee against credential egress should not rely on any of these and should scope the credentials themselves. +- **One image, every backend — a stated tradeoff.** The spoke image bundles + every supported CLI backend (Copilot, Codex, Claude Code, Goose, Antigravity, + muse, …) on one Node base, so an operator can assign backends per agent + role by configuration and a hosted spoke can switch backends when a + provider degrades, without an image rebuild. The cost is a large surface in + one image and no per-agent kernel boundary (weakness #2, + [#2804](https://github.com/hivecommons/hive/issues/2804)). Mitigations: + non-root UIDs per agent, `--ignore-scripts`, version/digest pinning with + per-arch checksums where upstream publishes them, and the MITM proxy as the + egress boundary regardless of which CLI is talking. The contributor path + already ships a separate, slimmer `Dockerfile.contributor`; the roadmap for + the resident spoke is per-backend image variants selected from the ACMM + pack, so a Copilot-only hive does not carry the others. - **Ed25519-only session/SSO verification** (`security-model.md` "Sessions and SSO are Ed25519-only") — the legacy HMAC session-cookie lane and fleet-wide shared heartbeat bearer were both removed in v4; a spoke @@ -469,7 +587,7 @@ project-level compliance signals: ### Development pipeline -- **Language and structure**: Go (`src/`, `go 1.25.6` per `src/go.mod:3`) for +- **Language and structure**: Go (`src/`, `go 1.26.6` per `src/go.mod:3`) for the core dashboard/hub/proxy/scheduler/agent-orchestration code; a JS dashboard UI served inline (no separate SPA build step); Python/Shell for the deterministic pre-kick pipeline (45 scripts, indexed in @@ -607,10 +725,11 @@ because a self-assessment that only lists strengths is not credible: agent's prompt (`security-threat-model.md` "Trust boundaries": *"Public issue authors can place arbitrary text in titles, labels, bodies, and comments that Hive may include in a kick"*). `ioscan`'s deterministic - rules and optional semantic classifier reduce this materially, but the + rules and optional semantic classifier reduce this materially. The **default `ioscan.fail_mode` is `open`** (`ioscan.md:11` — *"open (default) - redacts"*), meaning a scanner outage, timeout, or classifier failure fails - toward continuing to process input rather than halting it. The semantic + redacts"*): a Critical finding is redacted and the kick continues, rather + than the kick being blocked. The redaction itself is deterministic and does + not depend on any model call. The semantic (LLM-judge) classifier layer is explicitly **fail-open on errors/timeouts by design** (`ioscan.md:26`, ADR-0008: *"Classifier failures and budget exhaustion fail open"*) so a reviewer outage cannot itself become a @@ -847,16 +966,17 @@ repository and answered below. Where the answer is "no," it says no. wrong on a schedule. - **Has any informal security review or adversarial testing occurred?** - Resolved: **no, and this is the most significant "no" in the list.** There - is no red-team exercise, no adversarial evaluation, and no measured - detection rate for `ioscan` anywhere in the repository — the search for one - returned only the phrase used in unrelated design documents. The hardening - work referenced by issue number throughout `security-threat-model.md` is - maintainer-identified and maintainer-fixed, which is not the same thing as - adversarial review. A red-team evaluation of the injection path is tracked - in [#6685](https://github.com/hivecommons/hive/issues/6685). Until it - exists, every efficacy claim about `ioscan` in this document should be read - as unvalidated by design rather than validated by silence. + Resolved — and the answer changed between revisions. At first review the + honest answer was **no**: no red-team exercise and no measured detection + rate for `ioscan` existed anywhere in the repository. That gap was tracked + in [#6685](https://github.com/hivecommons/hive/issues/6685) and closed by + [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md): a 43-payload adversarial corpus + whose result (42% withheld, 58% reached the agent) is quoted above and + whose containment claim is verified in CI. What still has **not** occurred + is an *external* review: no third-party audit or penetration test, and the + red-team corpus was written by the maintainers. Efficacy claims about + `ioscan` in this document are now measured rather than asserted, but + measured by the people who built it. - **Will CODEOWNERS enforcement be enabled?** Resolved: the live `v4` branch protection currently requires **no** pull-request reviews at all, and From 76076d078085bed9781aafe0df67fb7517391da8 Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Thu, 1 Oct 2026 21:48:26 -0400 Subject: [PATCH 08/10] docs: align Hive assessment ioscan defaults Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/projects/hive-commons/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md index 78717f677..064d6fd2b 100644 --- a/projects/hive-commons/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -35,7 +35,7 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > | "Where are GitHub tokens and inference keys stored? What is compromised if an operator is? What threatens install/update?" | New [Credentials: where they live and what falls with them](#credentials-where-they-live-and-what-falls-with-them) — a storage table, a blast-radius table per actor, and the supply-chain facts for install/upgrade. | > | "How does hive authenticate a contributor/relay?" | New [Contributor relay authentication](#contributor-relay-authentication). | > | "Were threats identified on the hub↔spoke interface?" | New [Hub ↔ spoke interface](#hub--spoke-interface) with a threat table. One finding: hub→spoke config pushes rely on TLS alone and are not independently signed — filed as [#7082](https://github.com/hivecommons/hive/issues/7082). | -> | "What would `fail_mode: closed` and canaries-on by default cost? Are they partial mitigations? Plans?" | The document's own framing was wrong: `open` **redacts** and continues, it does not pass injection through. Corrected in three places. Defaults plan tracked in [#7083](https://github.com/hivecommons/hive/issues/7083). | +> | "What would `fail_mode: closed` and canaries-on by default cost? Are they partial mitigations? Plans?" | The document's own framing was wrong: `open` **redacts** and continues, it does not pass injection through. Corrected in three places. Defaults shipped in [#7095](https://github.com/hivecommons/hive/pull/7095) after being tracked in [#7083](https://github.com/hivecommons/hive/issues/7083). | > | "The red-team section duplicates `ioscan-red-team.md`." | Cut to a summary that links out. | > | "The image bundles every CLI backend — by design?" | Yes; stated as a tradeoff with its cost and the roadmap under [Security relevant components](#security-relevant-components). | > | "Some sections are dense." | Long paragraphs in the critical-components and weaknesses sections broken up or replaced with tables; a stale "no adversarial testing has occurred" answer in the appendix corrected. | @@ -301,7 +301,7 @@ control removes it; the controls bound the consequences. |---|---|---| | Attacker text talks an agent into **merging** malicious code | `PUT /pulls/{n}/merge` is **hard-denied for every ACMM mode** at the proxy (`rules.go:215-226`), as is the GraphQL merge mutation. The agent never holds a credential path to merge; `hive-merge` runs as Hive with a SHA-pinned eligibility binding. | `ioscan`. A sufficiently clever prompt defeats a scanner; it does not defeat a rule table the model never sees. | | Attacker text talks an agent into **opening a PR** with a backdoor | `POST /pulls` is likewise hard-denied for every mode. PR creation goes through `hive-open-pr` as the App bot, attribution-stamped and audit-logged. | Nothing prevents the *content* of a legitimately-created PR from being attacker-influenced. Review it like any other PR. | -| Attacker exfiltrates your **secrets** via the agent | Mode-tiered tokens mean low-tier agents never hold code-write credentials. Optional `ioscan` canaries detect prompt contents echoed into outbound GitHub writes at the proxy, including base64/hex/URL-encoded, reversed and split spellings of the token. | Canaries are **default-off**, and their transform list is finite — an encoding it does not model still passes. `git-receive-pack` bodies are unscannable, and non-GitHub egress is tunneled without inspection. | +| Attacker exfiltrates your **secrets** via the agent | Mode-tiered tokens mean low-tier agents never hold code-write credentials. `ioscan` canaries, which default on unless an operator sets `canaries: false`, detect prompt contents echoed into outbound GitHub writes at the proxy, including base64/hex/URL-encoded, reversed and split spellings of the token. | Canaries are not exhaustive: their transform list is finite, so an encoding it does not model still passes. `git-receive-pack` bodies are unscannable, and non-GitHub egress is tunneled without inspection. | | Agent burns your **inference budget** in a loop | Seven-day rolling token budget suppresses kicks on exhaustion. | Nothing caps the *rate* within budget. | | Compromised agent attacks **other agents** on the same spoke | Per-UID separation stops tmux attach and token-file reads. | Shared container/kernel. See weakness #2. | @@ -315,17 +315,20 @@ control removes it; the controls bound the consequences. 2. **Whether the governed repository is public.** A private repository with trusted collaborators collapses most of the untrusted-input surface. The threat model above is substantially a *public-repository* threat model. -3. **Whether you enabled `ioscan.canaries` and `fail_mode: closed`.** Both - default off. Be precise about what the defaults do: `fail_mode: open` +3. **Whether you accept or override the `ioscan` canary and fail-mode defaults.** + `ioscan.canaries` now defaults on everywhere (set `canaries: false` to opt + out). `ioscan.fail_mode` has a level-aware default: it stays `open` at + ACMM L1–L4, and resolves to `closed` at ACMM L5/L6 via the L5/L6 packs, + where agents can merge. An explicit per-hive `fail_mode` overrides the + level default either way. Be precise about what those modes do: `open` **redacts** a Critical finding and continues the kick — it does not pass the injection through; `closed` blocks the kick and writes an `ioscan_fail_closed` audit entry. The cost of `closed` is that every - Critical false positive becomes a stalled queue item needing an operator. - Canaries add a per-kick marker and an egress scan. Both are partial - mitigations (see below); a security-sensitive deployment should enable - both. The project's plan is to make canaries the default everywhere and - `closed` the default at ACMM ≥ L5, where agents can merge - ([#7083](https://github.com/hivecommons/hive/issues/7083)). + Critical false positive becomes a stalled queue item needing an operator; + that cost is now the default at L5/L6. Canaries add a per-kick marker and + an egress scan. Both are partial mitigations (see below), and the current + defaults shipped in [#7095](https://github.com/hivecommons/hive/pull/7095) + after being tracked in [#7083](https://github.com/hivecommons/hive/issues/7083). **What we would tell a new operator.** Start at L1–L3 on a repository you would not mind an agent filing a bad issue on. Read the attribution trailers @@ -424,7 +427,7 @@ repository writes: is default-off and its contribution is unmeasured; the corpus covers the input path only. - **Exfiltration detection (`ioscan.canaries`, default off).** A per-agent + **Exfiltration detection (`ioscan.canaries`, default on unless opted out).** A per-agent `HIVE-CANARY-<48 hex>` token is planted in the agent's prompt, and the egress proxy scans outbound GitHub request bodies for it (`github_proxy.go:1179-1205`): a hit is positive evidence that prompt @@ -726,9 +729,11 @@ because a self-assessment that only lists strengths is not credible: issue authors can place arbitrary text in titles, labels, bodies, and comments that Hive may include in a kick"*). `ioscan`'s deterministic rules and optional semantic classifier reduce this materially. The - **default `ioscan.fail_mode` is `open`** (`ioscan.md:11` — *"open (default) - redacts"*): a Critical finding is redacted and the kick continues, rather - than the kick being blocked. The redaction itself is deterministic and does + **default `ioscan.fail_mode` is level-aware** (`ioscan.md:10-11`): it is + `open` at ACMM L1–L4, where a Critical finding is redacted and the kick + continues, and `closed` at ACMM L5/L6 via the L5/L6 packs, where a Critical + finding blocks the kick. An explicit per-hive `fail_mode` overrides the + level default either way. The redaction itself is deterministic and does not depend on any model call. The semantic (LLM-judge) classifier layer is explicitly **fail-open on errors/timeouts by design** (`ioscan.md:26`, ADR-0008: *"Classifier failures and budget From 6617e1f91223264067b31118ba75fb5f8d04f714 Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Thu, 1 Oct 2026 22:08:49 -0400 Subject: [PATCH 09/10] docs: refresh Hive assessment factual drift Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 73 +++++++++---------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/projects/hive-commons/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md index 064d6fd2b..a5046b3a3 100644 --- a/projects/hive-commons/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -20,7 +20,7 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered, then **measured**: [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) runs a 43-payload adversarial corpus and publishes the result — **42% withheld, 58% reached the agent**, with the containment credited to the network deny rules and verified across all four ACMM modes on every test run ([#6685](https://github.com/hivecommons/hive/issues/6685)). | > | "What is redaction for? What about base64-encoded exfiltration?" | Log scrubbing re-scoped as log hygiene, explicitly **not** an exfiltration control. Running the question against the canary path found a real gap — the egress check was substring-only — filed as [#6686](https://github.com/hivecommons/hive/issues/6686) and **since fixed**: the proxy now decodes and normalizes outbound bodies before matching canaries. | > | "Get an OpenSSF passing badge." | **Already held, and this document was wrong to imply otherwise.** [Project 14261](https://www.bestpractices.dev/projects/14261) reached **passing** (100%) on 2026-08-27 — four days before the review — and `README.md` was displaying it throughout. The badge entry has since been corrected: 70 URLs in its criteria justifications still pointed at the pre-migration `kubestellar` org. Tracked in [#6684](https://github.com/hivecommons/hive/issues/6684). | -> | "This is a huge risk. Why not mitigate it?" | Half was mitigated: the roster went from **one maintainer to three**, across three affiliations, with a documented security-response process. The unmitigated half — unenforced code ownership — is now stated as the largest remaining process risk, with scoped enforcement tracked in [#6687](https://github.com/hivecommons/hive/issues/6687). | +> | "This is a huge risk. Why not mitigate it?" | Half was mitigated: the roster went from **one maintainer to three**, across three affiliations, with a documented security-response process. The unmitigated half — unenforced code ownership — is now stated as the largest remaining process risk, with scoped CODEOWNERS added but branch protection still unenforced. | > | "Looks like AI generated this — you should know the answer." | The "Case studies: not applicable" claim was simply **wrong**: `ADOPTERS.md` lists seven adopters, three in production, one running at ACMM L5/L6 across 43 repositories. Replaced with the real table. | > | "Go through the open questions and figure them out." | The open-questions section is gone. Every item was run down against the repository and answered in [Questions resolved since first review](#questions-resolved-since-first-review) — including two answers that are "no." | > @@ -65,7 +65,7 @@ writing) wherever a specific mechanism is asserted. | Assessment Stage | Complete | | Software | [hivecommons/hive](https://github.com/hivecommons/hive) | | Security Provider | No — Hive is not itself a security product. It is an agent-orchestration platform whose core value proposition includes constraining the blast radius of the AI agents it runs; see [Overview](#overview) below. | -| Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `src/bin/`, 45 scripts per [`bin/README.md`](https://github.com/hivecommons/hive/blob/v4/bin/README.md)) | +| Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `bin/`, indexed in [`bin/README.md`](https://github.com/hivecommons/hive/blob/v4/bin/README.md)) | | SBOM | Tagged releases publish standalone SPDX JSON SBOM release assets for `hive`, `hive-contributor`, and `hive-hub` (`hive-v-sbom.spdx.json`, `hive-contributor-v-sbom.spdx.json`, `hive-hub-v-sbom.spdx.json`) generated by Syft against the already-published GHCR images; see [releases.md](https://github.com/hivecommons/hive/blob/v4/src/docs/releases.md#software-bill-of-materials-sbom). These are deliberately **out-of-band** files, not in-image attestations. `docker.yml` keeps `provenance: false`/`sbom: false` (`docker.yml:295,346,631,818`) because `build-push-action` attestations force an OCI image index and reintroduced the #3760 container-runtime crash loop. The guard in `src/scripts/check-no-image-attestations.sh` asserts the image builds keep plain manifests. | | Security links | See table below | @@ -84,8 +84,8 @@ writing) wherever a specific mechanism is asserted. Hive orchestrates fleets of AI coding-agent processes (backends: Claude, GitHub Copilot, Gemini, Goose, Bob, Agy) that autonomously maintain software -projects hosted on GitHub (and GitHub Enterprise/GitLab/Gitea via the -"Forge App" abstraction) — filing issues, opening pull requests, reviewing +projects hosted on GitHub and GitHub Enterprise — filing issues, opening pull +requests, reviewing code, and, at the highest autonomy setting, merging. Agents run as CLI subprocesses inside tmux sessions, in a container or Kubernetes pod, and authenticate to the source-control provider with a GitHub App installation @@ -271,7 +271,7 @@ any external contributor's PR and is never merge-eligible on its own. - Hive does not sandbox agent code execution at the level of per-run containers or microVMs today — agents share one container's process namespace, separated by per-UID isolation, not process/kernel isolation. - This is a documented, open, tracked gap (issue #2804 — see + This is a documented gap (issue #2804; see `security-threat-model.md` "Residual risks and known gaps"). - Hive does not provide a general-purpose network content firewall. The MITM proxy inspects `api.github.com` (and, per `src/pkg/proxy/rules.go:78-80`, @@ -302,13 +302,13 @@ control removes it; the controls bound the consequences. | Attacker text talks an agent into **merging** malicious code | `PUT /pulls/{n}/merge` is **hard-denied for every ACMM mode** at the proxy (`rules.go:215-226`), as is the GraphQL merge mutation. The agent never holds a credential path to merge; `hive-merge` runs as Hive with a SHA-pinned eligibility binding. | `ioscan`. A sufficiently clever prompt defeats a scanner; it does not defeat a rule table the model never sees. | | Attacker text talks an agent into **opening a PR** with a backdoor | `POST /pulls` is likewise hard-denied for every mode. PR creation goes through `hive-open-pr` as the App bot, attribution-stamped and audit-logged. | Nothing prevents the *content* of a legitimately-created PR from being attacker-influenced. Review it like any other PR. | | Attacker exfiltrates your **secrets** via the agent | Mode-tiered tokens mean low-tier agents never hold code-write credentials. `ioscan` canaries, which default on unless an operator sets `canaries: false`, detect prompt contents echoed into outbound GitHub writes at the proxy, including base64/hex/URL-encoded, reversed and split spellings of the token. | Canaries are not exhaustive: their transform list is finite, so an encoding it does not model still passes. `git-receive-pack` bodies are unscannable, and non-GitHub egress is tunneled without inspection. | -| Agent burns your **inference budget** in a loop | Seven-day rolling token budget suppresses kicks on exhaustion. | Nothing caps the *rate* within budget. | +| Agent burns your **inference budget** in a loop | A configurable token-budget window (default seven days) suppresses kicks on exhaustion. | Nothing caps the *rate* within budget. | | Compromised agent attacks **other agents** on the same spoke | Per-UID separation stops tmux attach and token-file reads. | Shared container/kernel. See weakness #2. | **The three settings that actually determine your exposure**, in order: -1. **Your ACMM level.** At L1–L3 an agent can observe and file issues but - cannot write code; at L6 it can merge. This single dial moves prompt +1. **Your ACMM level.** At L1–L2 an agent does not write code; at L3 + `quality` may open hold-gated PRs; only L6 auto-merges. This single dial moves prompt templates, credential scope, CLI tool-denies and proxy rules together. It is the control to reason about first, and it is the one an operator chooses rather than inherits. @@ -346,11 +346,11 @@ choose an autonomy level with that outcome in mind rather than the happy path. ## Self-assessment use This self-assessment is created by the Hive maintainers to perform an initial -evaluation of the project's security posture as part of the CNCF Incubation +evaluation of the project's security posture as part of the CNCF Sandbox application process. It is not a substitute for a third-party audit or penetration test — neither has been performed on this project to date (see [Security issue resolution](#security-issue-resolution)). TAG-Security and -the CNCF community may use it to assess Hive for Incubation and may request +the CNCF community may use it to assess Hive for Sandbox and may request a joint or independent assessment building on it. This document reflects the project's understanding of its own architecture at the time of writing and carries no warranty; it should not be relied upon exclusively to assess a @@ -489,8 +489,8 @@ repository writes: transcript tail and can pause/alert on divergence. Explicitly semantic oversight, not a structural control, and fails open on reviewer outage (per `security-threat-model.md` residual risks). -- **Token budget** — a seven-day rolling token budget that suppresses kicks - on exhaustion, limiting denial-of-wallet from a runaway or compromised +- **Token budget** — a configurable token-budget window (default seven days) + that suppresses kicks on exhaustion, limiting denial-of-wallet from a runaway or compromised agent loop. - **Log scrubbing** (`src/pkg/logscrub`, `security.md`) — redacts eight categories from Hive's own structured log output: GitHub token prefixes @@ -544,7 +544,7 @@ repository writes: (`src/Dockerfile:8,50,78`; `actions/checkout@3d3c42e...` in `.github/workflows/docker.yml:85,280,318`); `npm install --ignore-scripts` for all global AI-CLI installs. -- **OpenSSF Scorecard** — runs weekly and on push to `main`/`v4` +- **OpenSSF Scorecard** — runs weekly and on the configured branch pushes (`.github/workflows/scorecard.yml`), via a shared reusable workflow pinned by commit SHA. @@ -554,7 +554,7 @@ Hive does not currently hold any formal security certification (e.g. FIPS, Common Criteria, SOC 2) and makes no claim to one. Relevant project-level compliance signals: -- **OpenSSF Scorecard**: automated, runs weekly and on push to `main`/`v4` +- **OpenSSF Scorecard**: automated, runs weekly and on the configured branch pushes (`scorecard.yml`, via a SHA-pinned reusable workflow in `hivecommons/infra`); results publish to the repository's code-scanning alerts. No specific score floor is gated in CI at present. @@ -593,13 +593,12 @@ project-level compliance signals: - **Language and structure**: Go (`src/`, `go 1.26.6` per `src/go.mod:3`) for the core dashboard/hub/proxy/scheduler/agent-orchestration code; a JS dashboard UI served inline (no separate SPA build step); Python/Shell for - the deterministic pre-kick pipeline (45 scripts, indexed in - `bin/README.md`). -- **Branch model**: `v4` is the sole actively maintained line; - `v2` was retired in August 2026 (`src/docs/README.md` header, `migration-v2-v4.md`). + the deterministic pre-kick pipeline (indexed in `bin/README.md`). +- **Branch model**: `v5` is the actively maintained line; `v4` is no longer + maintained, and `v2` was retired in August 2026 (`src/docs/documentation-map.md`, `migration-v2-v4.md`). - **CI gating**: PR-triggered test execution runs from `.github/workflows/v2-tests.yml` (name is a historical artifact of the - branch-rename; it is the workflow that gates `v4` PRs) as a sharded + branch-rename; it is the workflow that gates maintained-line PRs) as a sharded `go test -short -race -count=1` run, with an hourly full-suite monitor in `coverage-hourly.yml` that additionally auto-files an issue on a coverage regression. Coverage floors are intentionally duplicated between the two @@ -631,7 +630,7 @@ project-level compliance signals: Dockerfiles, workflow definitions, deploy manifests, SUID contract checks, and key/cookie/session handling), and every entry names all three current maintainers (`@clubanderson`, `@hanthor`, `@Danathar`). The remaining - repo-side step is enabling "Require review from Code Owners" in `v4` branch + repo-side step is enabling "Require review from Code Owners" in `v5` branch protection; until that is enabled, CODEOWNERS is still advisory rather than enforced — see [Known weaknesses](#three-most-significant-known-weaknesses). @@ -662,8 +661,8 @@ project-level compliance signals: Hive is an independent project in the [hivecommons](https://github.com/hivecommons) org (transferred out of the KubeStellar org on 2026-09-03, where it was -incubated as a subproject). It interoperates with, but does not depend on: GitHub/GitHub Enterprise/GitLab/Gitea (via the "Forge App" -abstraction), several AI coding-agent CLI backends (Claude Code, GitHub +incubated as a subproject). It interoperates with, but does not depend on: GitHub/GitHub Enterprise; GitLab/Gitea adapters exist but are not wired +for production use. It also interoperates with several AI coding-agent CLI backends (Claude Code, GitHub Copilot CLI, Gemini, Goose, Bob/bobshell, Agy), and self-hosted inference gateways (LiteLLM, vLLM, llm-d, watsonx) reached only through an in-pod credential-translating proxy (`security-model.md` Layer 3). It is @@ -693,9 +692,10 @@ page deliberately does not restate the roster, pointing at `OWNERS` instead so a second list cannot drift. Remaining gaps, stated rather than implied: there is **no published -CVSS-scoring policy** and **no maximum time-to-fix SLA** beyond asking +CVSS-scoring policy** and **no private-report time-to-fix SLA** beyond the +60-day public-vulnerability commitment in `security-response.md` and asking reporters for "a reasonable opportunity to remediate." The acknowledgement -target is a commitment; time-to-fix is not. +target is a commitment; private-report time-to-fix is not. ### Incident response @@ -748,7 +748,7 @@ because a self-assessment that only lists strengths is not credible: turning reviewer outages into scheduler outages."* 2. **Shared-container execution is a materially weaker isolation boundary - than per-run sandboxing, and this is an open, tracked gap.** Agents run as + than per-run sandboxing, and this remains a documented gap.** Agents run as separate Unix UIDs inside one Hive container/pod, not in separate containers or microVMs. Per-UID separation (`security-model.md` Layer 4) stops one agent from attaching to another's tmux session or reading its @@ -758,11 +758,10 @@ because a self-assessment that only lists strengths is not credible: every other agent in the pod. `security-threat-model.md` names this directly under "Residual risks and known gaps": *"Shared-container execution remains a material risk... it is not equivalent to per-run - containers or microVMs,"* tracked in open issue - [#2804](https://github.com/hivecommons/hive/issues/2804), which — per the - same doc — also proposes moving live GitHub write credentials out of the + containers or microVMs,"* and issue + [#2804](https://github.com/hivecommons/hive/issues/2804) also proposed moving live GitHub write credentials out of the agent sandbox entirely (*"current agents can still need live credentials - to push/open PRs"*). Until #2804 lands, a compromised agent process that + to push/open PRs"*). Until that gap is closed, a compromised agent process that evades the network/token controls still executes inside the same container as every other agent on that spoke. @@ -785,7 +784,7 @@ because a self-assessment that only lists strengths is not credible: Dockerfiles, CI workflows, deploy manifests, SUID contract checks, proxy policy, and key/cookie/session handling — and lists all three current maintainers on every entry. But "Require review from Code Owners" still - has to be enabled in `v4` branch protection after the scoped file lands. + has to be enabled in `v5` branch protection. Until then, a change to the MITM proxy's deny-rule table — the control this document credits as the thing an attacker cannot argue with — can merge on green CI with no human security reviewer. @@ -851,7 +850,7 @@ development, not externally reported vulnerabilities. ### Open SSF best practices An [OpenSSF Scorecard](https://github.com/hivecommons/hive/blob/v4/.github/workflows/scorecard.yml) -workflow runs weekly and on push to `main`/`v4`, publishing to the +workflow runs weekly and on the configured branch pushes, publishing to the repository's code-scanning alerts. This assessment deliberately does not freeze a numeric score into the text — it moves independently of this document — and a reviewer should pull the current result. @@ -914,7 +913,7 @@ was wrong on the facts and is corrected here. Hive is the flagship of the [Hive Commons](https://hivecommons.dev) project family and originated as a subproject of [KubeStellar](https://github.com/kubestellar) (CNCF Sandbox), which remains its first production adopter. It interoperates -with, but is not a vendor dependency of: GitHub/GitHub Enterprise/GitLab/Gitea, and multiple AI CLI +with, but is not a vendor dependency of: GitHub/GitHub Enterprise, with GitLab/Gitea adapters not wired for production use, and multiple AI CLI backend vendors (Anthropic Claude Code, GitHub Copilot CLI, Google Gemini, Block Goose, IBM Bob). See [landscape.md](https://github.com/hivecommons/hive/blob/v4/src/docs/landscape.md) for a maintained comparison against nearby agentic-orchestration tools. @@ -964,7 +963,7 @@ repository and answered below. Where the answer is "no," it says no. written from itself rather than checked against the programme's API. - **What is the current OpenSSF Scorecard result?** Intentionally not frozen - into this document — the workflow runs weekly and on every push to `v4`, + into this document — the workflow runs weekly and on the configured branch pushes, and a reviewer should read the live result rather than a stale number. This is the one item from the original list that remains deliberately unanswered here, and the reason is that quoting it would make the document @@ -987,8 +986,6 @@ repository and answered below. Where the answer is "no," it says no. protection currently requires **no** pull-request reviews at all, and enforcement was blocked on the fact that the project's own automation merges green PRs. The intended resolution is scoped enforcement over - security-critical paths only, tracked in - [#6687](https://github.com/hivecommons/hive/issues/6687) along with - expanding `CODEOWNERS` from one owner to the three current maintainers. - It is a commitment with an issue behind it, not a plan to remain advisory - indefinitely. + security-critical paths only, with `CODEOWNERS` expanded from one owner to + the three current maintainers. It is a commitment, not a plan to remain + advisory indefinitely. From 9e7ce93b82a162cc7e56ac67956e5ebce34f53eb Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Fri, 2 Oct 2026 08:19:13 -0400 Subject: [PATCH 10/10] docs: point Hive assessment mirror at v5 Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 72 ++++++++++--------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/projects/hive-commons/security-assessment/self-assessment.md b/projects/hive-commons/security-assessment/self-assessment.md index a5046b3a3..3b7969322 100644 --- a/projects/hive-commons/security-assessment/self-assessment.md +++ b/projects/hive-commons/security-assessment/self-assessment.md @@ -7,7 +7,7 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > **Scope:** This assessment covers **[hivecommons/hive](https://github.com/hivecommons/hive)** only — the AI agent orchestration system and its hub/spoke deployment. Hive was incubated as a subproject of KubeStellar and was transferred to its own vendor-neutral org, [hivecommons](https://github.com/hivecommons), on 2026-09-03; this assessment does **not** cover [KubeStellar Core](https://github.com/kubestellar/kubestellar) or [KubeStellar Console](https://github.com/kubestellar/console), which has its [own self-assessment](https://github.com/cncf/toc/blob/main/projects/kubestellar/sub-projects/console/security-assessment/self-assessment.md). > -> **Canonical source:** this document is maintained in the Hive repository at [`src/docs/security-self-assessment.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-self-assessment.md). Corrections should be made there and mirrored here. +> **Canonical source:** this document is maintained in the Hive repository at [`src/docs/security-self-assessment.md`](https://github.com/hivecommons/hive/blob/v5/src/docs/security-self-assessment.md). Corrections should be made there and mirrored here. > **Revision 2 — changes made in response to TAG-Security review > ([cncf/toc#2286](https://github.com/cncf/toc/pull/2286)).** Seven review @@ -17,7 +17,7 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > | Review point | Change | > |---|---| > | "If I deploy this, what should I worry about?" | New section [If you deploy this, what should you worry about?](#if-you-deploy-this-what-should-you-worry-about) — the attack path stated plainly, a concern/mitigation/non-mitigation table, the three settings that determine exposure, and the worst realistic outcome. | -> | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered, then **measured**: [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) runs a 43-payload adversarial corpus and publishes the result — **42% withheld, 58% reached the agent**, with the containment credited to the network deny rules and verified across all four ACMM modes on every test run ([#6685](https://github.com/hivecommons/hive/issues/6685)). | +> | "Have you red teamed `ioscan`? Is this perfect defense or partial mitigation?" | Answered, then **measured**: [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v5/src/docs/ioscan-red-team.md) runs a 43-payload adversarial corpus and publishes the result — **42% withheld, 58% reached the agent**, with the containment credited to the network deny rules and verified across all four ACMM modes on every test run ([#6685](https://github.com/hivecommons/hive/issues/6685)). | > | "What is redaction for? What about base64-encoded exfiltration?" | Log scrubbing re-scoped as log hygiene, explicitly **not** an exfiltration control. Running the question against the canary path found a real gap — the egress check was substring-only — filed as [#6686](https://github.com/hivecommons/hive/issues/6686) and **since fixed**: the proxy now decodes and normalizes outbound bodies before matching canaries. | > | "Get an OpenSSF passing badge." | **Already held, and this document was wrong to imply otherwise.** [Project 14261](https://www.bestpractices.dev/projects/14261) reached **passing** (100%) on 2026-08-27 — four days before the review — and `README.md` was displaying it throughout. The badge entry has since been corrected: 70 URLs in its criteria justifications still pointed at the pre-migration `kubestellar` org. Tracked in [#6684](https://github.com/hivecommons/hive/issues/6684). | > | "This is a huge risk. Why not mitigate it?" | Half was mitigated: the roster went from **one maintainer to three**, across three affiliations, with a documented security-response process. The unmitigated half — unenforced code ownership — is now stated as the largest remaining process risk, with scoped CODEOWNERS added but branch protection still unenforced. | @@ -34,7 +34,7 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). > |---|---| > | "Where are GitHub tokens and inference keys stored? What is compromised if an operator is? What threatens install/update?" | New [Credentials: where they live and what falls with them](#credentials-where-they-live-and-what-falls-with-them) — a storage table, a blast-radius table per actor, and the supply-chain facts for install/upgrade. | > | "How does hive authenticate a contributor/relay?" | New [Contributor relay authentication](#contributor-relay-authentication). | -> | "Were threats identified on the hub↔spoke interface?" | New [Hub ↔ spoke interface](#hub--spoke-interface) with a threat table. One finding: hub→spoke config pushes rely on TLS alone and are not independently signed — filed as [#7082](https://github.com/hivecommons/hive/issues/7082). | +> | "Were threats identified on the hub↔spoke interface?" | New [Hub ↔ spoke interface](#hub--spoke-interface) with a threat table. The finding that hub→spoke config pushes relied on TLS alone ([#7082](https://github.com/hivecommons/hive/issues/7082), closed 2026-09-15) is now **mitigated**: responses are Ed25519-signed, verified by the spoke, and bound to `hive_id` plus a monotonic `seq`; enforcement is opt-in with `HIVE_HEARTBEAT_VERIFY=enforce`, while the default logs failed signatures and still applies the response. | > | "What would `fail_mode: closed` and canaries-on by default cost? Are they partial mitigations? Plans?" | The document's own framing was wrong: `open` **redacts** and continues, it does not pass injection through. Corrected in three places. Defaults shipped in [#7095](https://github.com/hivecommons/hive/pull/7095) after being tracked in [#7083](https://github.com/hivecommons/hive/issues/7083). | > | "The red-team section duplicates `ioscan-red-team.md`." | Cut to a summary that links out. | > | "The image bundles every CLI backend — by design?" | Yes; stated as a tradeoff with its cost and the roadmap under [Security relevant components](#security-relevant-components). | @@ -43,19 +43,19 @@ application ([cncf/sandbox#516](https://github.com/cncf/sandbox/issues/516)). It complements, and deliberately does not duplicate, three existing security documents in the Hive repository: -- [security-threat-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-threat-model.md) — attacker-oriented +- [security-threat-model.md](https://github.com/hivecommons/hive/blob/v5/src/docs/security-threat-model.md) — attacker-oriented view: assets, trust boundaries, threat actors, defense layers, residual risks. -- [security-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-model.md) — operator/evaluator-oriented view: +- [security-model.md](https://github.com/hivecommons/hive/blob/v5/src/docs/security-model.md) — operator/evaluator-oriented view: the seven enforcement layers (dashboard auth, spoke auth, credential isolation, sandboxing, GitHub blast-radius controls, hub↔spoke channel, hosted-platform isolation) with file/line evidence for each. -- [security.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security.md) — log-scrubbing and secret-redaction +- [security.md](https://github.com/hivecommons/hive/blob/v5/src/docs/security.md) — log-scrubbing and secret-redaction implementation notes. Where this document repeats a claim from those pages, it cites the same evidence rather than re-deriving it. Sections below cite `path:line` against -the Hive repository's `v4` branch (`src/` prefix; commit `327969b0` at time of +the Hive repository's `v5` branch (`src/` prefix; commit `baa7dacc7` at time of writing) wherever a specific mechanism is asserted. ## Metadata @@ -65,18 +65,18 @@ writing) wherever a specific mechanism is asserted. | Assessment Stage | Complete | | Software | [hivecommons/hive](https://github.com/hivecommons/hive) | | Security Provider | No — Hive is not itself a security product. It is an agent-orchestration platform whose core value proposition includes constraining the blast radius of the AI agents it runs; see [Overview](#overview) below. | -| Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `bin/`, indexed in [`bin/README.md`](https://github.com/hivecommons/hive/blob/v4/bin/README.md)) | -| SBOM | Tagged releases publish standalone SPDX JSON SBOM release assets for `hive`, `hive-contributor`, and `hive-hub` (`hive-v-sbom.spdx.json`, `hive-contributor-v-sbom.spdx.json`, `hive-hub-v-sbom.spdx.json`) generated by Syft against the already-published GHCR images; see [releases.md](https://github.com/hivecommons/hive/blob/v4/src/docs/releases.md#software-bill-of-materials-sbom). These are deliberately **out-of-band** files, not in-image attestations. `docker.yml` keeps `provenance: false`/`sbom: false` (`docker.yml:295,346,631,818`) because `build-push-action` attestations force an OCI image index and reintroduced the #3760 container-runtime crash loop. The guard in `src/scripts/check-no-image-attestations.sh` asserts the image builds keep plain manifests. | +| Languages | Go (core: dashboard, hub, proxy, scheduler, agent orchestration — `src/go.mod`); JavaScript (dashboard UI, served inline, no separate SPA build — see `dashboard/`); Shell/Python (deterministic pipeline scripts under `bin/`, indexed in [`bin/README.md`](https://github.com/hivecommons/hive/blob/v5/bin/README.md)) | +| SBOM | Tagged releases publish standalone SPDX JSON SBOM release assets for `hive`, `hive-contributor`, and `hive-hub` (`hive-v-sbom.spdx.json`, `hive-contributor-v-sbom.spdx.json`, `hive-hub-v-sbom.spdx.json`) generated by Syft against the already-published GHCR images; see [releases.md](https://github.com/hivecommons/hive/blob/v5/src/docs/releases.md#software-bill-of-materials-sbom). These are deliberately **out-of-band** files, not in-image attestations. `docker.yml` keeps `provenance: false`/`sbom: false` (`docker.yml:295,346,631,818`) because `build-push-action` attestations force an OCI image index and reintroduced the #3760 container-runtime crash loop. The guard in `src/scripts/check-no-image-attestations.sh` asserts the image builds keep plain manifests. | | Security links | See table below | | Doc | URL | |---|---| -| Security policy / vulnerability reporting | [SECURITY.md](https://github.com/hivecommons/hive/blob/v4/SECURITY.md) | -| Threat model | [security-threat-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-threat-model.md) | -| Security model (operator guide) | [security-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-model.md) | -| Log scrubbing / secret redaction | [security.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security.md) | -| ADRs (architecture decision records) | [adr/README.md](https://github.com/hivecommons/hive/blob/v4/src/docs/adr/README.md) | -| OpenSSF Scorecard workflow | [.github/workflows/scorecard.yml](https://github.com/hivecommons/hive/blob/v4/.github/workflows/scorecard.yml) | +| Security policy / vulnerability reporting | [SECURITY.md](https://github.com/hivecommons/hive/blob/v5/SECURITY.md) | +| Threat model | [security-threat-model.md](https://github.com/hivecommons/hive/blob/v5/src/docs/security-threat-model.md) | +| Security model (operator guide) | [security-model.md](https://github.com/hivecommons/hive/blob/v5/src/docs/security-model.md) | +| Log scrubbing / secret redaction | [security.md](https://github.com/hivecommons/hive/blob/v5/src/docs/security.md) | +| ADRs (architecture decision records) | [adr/README.md](https://github.com/hivecommons/hive/blob/v5/src/docs/adr/README.md) | +| OpenSSF Scorecard workflow | [.github/workflows/scorecard.yml](https://github.com/hivecommons/hive/blob/v5/.github/workflows/scorecard.yml) | ## Overview @@ -103,7 +103,7 @@ issue, PR, comment, or label on a governed repository is potential agent input, and agents that reach the higher autonomy tiers can push code and open pull requests under real (scoped) GitHub credentials. The project's security posture is therefore built around the principle stated at the top of -[security-model.md](https://github.com/hivecommons/hive/blob/v4/src/docs/security-model.md): *"if a human would give the same +[security-model.md](https://github.com/hivecommons/hive/blob/v5/src/docs/security-model.md): *"if a human would give the same answer every time, it belongs in infrastructure, not in a prompt."* Enforcement is intended to sit in deterministic Go/shell code — a network proxy, a token scope, a file permission — rather than in an instruction the model is asked to @@ -121,7 +121,7 @@ obey. that reaches agent prompts. - **Contributors via ClankeR relay** — external contributors who donate compute by running an agent against a hive's queue over a relay protocol - (see [contributor-relay.md](https://github.com/hivecommons/hive/blob/v4/src/docs/contributor-relay.md) and + (see [contributor-relay.md](https://github.com/hivecommons/hive/blob/v5/src/docs/contributor-relay.md) and [Contributor relay authentication](#contributor-relay-authentication) below). Their machines are outside Hive's trust boundary. - **Hub operators / SaaS platform operators** — run the central hub that @@ -201,12 +201,16 @@ updating are supply-chain threats, and the current facts are: ### Hub ↔ spoke interface Registered spokes heartbeat to a hub; the hub answers with configuration and, -for hosted spokes, credentials. The two directions are not equally protected. +for hosted spokes, credentials. Both directions are now cryptographically +authenticated (spoke→hub by a per-hive bearer, hub→spoke by an Ed25519 +signature verified by the spoke — [#7082](https://github.com/hivecommons/hive/issues/7082)), but heartbeat signature +enforcement is opt-in (`HIVE_HEARTBEAT_VERIFY=enforce`) and the **trust** is still asymmetric: the hub is the root of trust that provisions and +signs, and a compromised hub can sign a genuine malicious push. | Direction | What is sent | How it is authenticated | |---|---|---| | **Spoke → hub** (heartbeat) | Operational telemetry: agent states, queue depth, version, health. **Never credentials.** | A **per-hive derived bearer** (`keyderive.PerHiveKey`, bound to trust domain and hive ID), verified against every live master generation so the master can rotate without a flag day (`src/pkg/hub/hub_keys.go`, `verifyHeartbeatBearerAcrossGenerations`). The fleet-wide shared bearer lane of earlier releases is **deleted**. | -| **Hub → spoke** (heartbeat response) | Configuration deltas; for hosted spokes, the spoke's GitHub App credentials and authorized-user list. | **TLS to the spoke's configured hub URL — and nothing else.** The response body is not signed and is not bound to a hive ID or sequence number. | +| **Hub → spoke** (heartbeat response) | Configuration deltas; for hosted spokes, the spoke's GitHub App credentials and authorized-user list. | **TLS plus an independent Ed25519 signature** over the response body ([#7082](https://github.com/hivecommons/hive/issues/7082)). The hub signs each response with the **same** master-derived Ed25519 key it already uses for SSO/session tokens (`infoSSOEd25519Seed`); the spoke verifies with the public key it already holds (`HIVE_SSO_PUBLIC_KEY`) — no new key or distribution. The signed body is bound to `hive_id` (defeats cross-hive replay) and a per-hive monotonic `seq`/timestamp (defeats rollback replay). Spokes default to **log-only** (verify, log failures, still accept) and reject only under opt-in `HIVE_HEARTBEAT_VERIFY=enforce`, and only after they have accepted one valid signed response (**trust-on-first-signed**), so a spoke never hard-fails against a hub that has not yet shipped signing. See `src/pkg/spoke` and `src/pkg/hub/heartbeat_signing.go`. | | **Hub-minted tokens** (SSO, delegation, session cookies) | Identity assertions the spoke must verify. | **Ed25519**; the spoke holds only the public key (`HIVE_SSO_PUBLIC_KEY`, `src/pkg/delegation/token.go`). A spoke without a key fails closed (503). | Threats identified on this interface: @@ -215,7 +219,7 @@ Threats identified on this interface: |---|---| | **Hub compromise → fleet-wide credential and config push** | Real and unmitigated by design of the lane; bounded only by hub hardening and by each spoke holding its own App key alone. Stated as the system's highest-value target. | | **Spoke impersonation** to the hub | Bounded. One leaked bearer authenticates one hive; the hub will not accept it for another hive ID, and rotation retires it within the dual-generation window. | -| **Replay, rollback, or mis-delivery of a pushed configuration** (a TLS-terminating middlebox, a misconfigured `HIVE_HUB_URL`, a captured response replayed to a different hive) | **Open.** Filed as [#7082](https://github.com/hivecommons/hive/issues/7082): sign the response with the hub's existing Ed25519 key and bind it to `hive_id` plus a monotonic sequence, rolling out log-only before enforcing. | +| **Replay, rollback, or mis-delivery of a pushed configuration** (a TLS-terminating middlebox, a misconfigured `HIVE_HUB_URL`, a captured response replayed to a different hive) | **Mitigated ([#7082](https://github.com/hivecommons/hive/issues/7082)).** The heartbeat response is now signed with the hub's existing Ed25519 key and bound to `hive_id` plus a monotonic `seq`/timestamp, so a middlebox or mis-pointed hub URL cannot forge config/credentials, a response captured for hive A cannot be replayed to hive B (`hive_id` binding), and an old response cannot roll config back (`seq` floor). Enforcement is opt-in (`HIVE_HEARTBEAT_VERIFY=enforce`); by default a failed signature is logged and the response is still applied, so deployed spokes are never bricked against an un-upgraded hub. The residual **hub-compromise** row above is unchanged: a genuine hub can still sign a genuine (malicious) push. | | **Telemetry disclosure** | Low. Heartbeats carry no secrets; the hub-side view is admin-gated. | ### Contributor relay authentication @@ -235,7 +239,7 @@ rather than trusting the relay's output: constant time (`contributorProfileFromRegistrationToken`). - **Authorization.** Every contributor has a **trust tier** with per-tier rate limits and model admission - ([contributor-trust-and-roles.md](https://github.com/hivecommons/hive/blob/v4/src/docs/contributor-trust-and-roles.md)). + ([contributor-trust-and-roles.md](https://github.com/hivecommons/hive/blob/v5/src/docs/contributor-trust-and-roles.md)). - **Per-task credential.** The hub mints a **55-minute** GitHub token scoped to the assigned task and re-mints it while the task is live; the lease is fenced to that contributor identity and abandoned after 30 minutes without @@ -405,7 +409,7 @@ repository writes: decoded is attacker-influenced. **How well does it work? Measured: a partial, uneven mitigation.** - [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md) runs a 43-payload adversarial + [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v5/src/docs/ioscan-red-team.md) runs a 43-payload adversarial corpus across six technique families against the shipped rules and publishes the per-case table. The headline: @@ -584,7 +588,7 @@ project-level compliance signals: assets, generated by Syft against the already-published GHCR images. They are intentionally not attached to image manifests; the container-runtime reason is explained under [Metadata](#metadata) and in - [releases.md](https://github.com/hivecommons/hive/blob/v4/src/docs/releases.md#software-bill-of-materials-sbom). + [releases.md](https://github.com/hivecommons/hive/blob/v5/src/docs/releases.md#software-bill-of-materials-sbom). ## Secure development practices @@ -674,7 +678,7 @@ independent of any single cloud provider or AI vendor. Vulnerability reports are handled through **GitHub private vulnerability reporting** (Security tab → "Report a vulnerability"), not public issues, PRs, -or discussions, per [`SECURITY.md`](https://github.com/hivecommons/hive/blob/v4/SECURITY.md). +or discussions, per [`SECURITY.md`](https://github.com/hivecommons/hive/blob/v5/SECURITY.md). Reporters are asked for affected component/branch/commit, description and impact, reproduction steps, and any supporting logs/PoC/config. @@ -682,7 +686,7 @@ impact, reproduction steps, and any supporting logs/PoC/config. within **5 business days** (`SECURITY.md` "What to Expect"), followed by investigation/confirmation, a coordinated fix and disclosure timeline, and optional reporter credit. Who performs that work is now documented: -[`security-response.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-response.md) +[`security-response.md`](https://github.com/hivecommons/hive/blob/v5/src/docs/security-response.md) establishes that security response is a duty of the **Maintainer Committee** — there is no separate security team, the committee *is* the response team — and that any of the three maintainers can receive and triage a report, with @@ -700,10 +704,10 @@ target is a commitment; private-report time-to-fix is not. ### Incident response A security-specific response process is documented in -[`security-response.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-response.md) +[`security-response.md`](https://github.com/hivecommons/hive/blob/v5/src/docs/security-response.md) — who responds, how a report is triaged, and how disclosure is coordinated — distinct from -[`docs/HUB_DISASTER_RECOVERY.md`](https://github.com/hivecommons/hive/blob/v4/docs/HUB_DISASTER_RECOVERY.md), +[`docs/HUB_DISASTER_RECOVERY.md`](https://github.com/hivecommons/hive/blob/v5/docs/HUB_DISASTER_RECOVERY.md), which covers hub-level disaster recovery (backup/restore, spoke fleet recovery, operator communication) and is an operational rather than security runbook. The master-key rotation flow (`security-model.md` "Master key @@ -806,7 +810,7 @@ because a self-assessment that only lists strengths is not credible: A secondary, narrower point worth surfacing alongside the three above: the **audit log's retention is size-triggered, not time-triggered** — rotation occurs at 5 MB with 3 backups retained -(`src/pkg/dashboard/audit.go:23-24`, `auditMaxSizeMB = 5`, +(`src/pkg/dashboard/audit.go:25-26`, `auditMaxSizeMB = 5`, `auditMaxBackups = 3`; a 90-day `auditMaxAgeDays` cap also applies but only prunes files already past the size-based rotation). On a busy hive with many audited actions per day, the effective lookback window this provides an @@ -849,7 +853,7 @@ development, not externally reported vulnerabilities. ### Open SSF best practices -An [OpenSSF Scorecard](https://github.com/hivecommons/hive/blob/v4/.github/workflows/scorecard.yml) +An [OpenSSF Scorecard](https://github.com/hivecommons/hive/blob/v5/.github/workflows/scorecard.yml) workflow runs weekly and on the configured branch pushes, publishing to the repository's code-scanning alerts. This assessment deliberately does not freeze a numeric score into the text — it moves independently of this @@ -878,7 +882,7 @@ stale. The badge status above is taken from the programme's public API. ### Case studies -Hive maintains an [`ADOPTERS.md`](https://github.com/hivecommons/hive/blob/v4/ADOPTERS.md) +Hive maintains an [`ADOPTERS.md`](https://github.com/hivecommons/hive/blob/v5/ADOPTERS.md) file with seven organizations, three of them at **Production** maturity. The security-relevant point is not the count but that these are deployments where the threat model in this document is live — real repositories, real @@ -915,7 +919,7 @@ family and originated as a subproject of [KubeStellar](https://github.com/kubest (CNCF Sandbox), which remains its first production adopter. It interoperates with, but is not a vendor dependency of: GitHub/GitHub Enterprise, with GitLab/Gitea adapters not wired for production use, and multiple AI CLI backend vendors (Anthropic Claude Code, GitHub Copilot CLI, Google Gemini, -Block Goose, IBM Bob). See [landscape.md](https://github.com/hivecommons/hive/blob/v4/src/docs/landscape.md) +Block Goose, IBM Bob). See [landscape.md](https://github.com/hivecommons/hive/blob/v5/src/docs/landscape.md) for a maintained comparison against nearby agentic-orchestration tools. ## Questions resolved since first review @@ -949,7 +953,7 @@ repository and answered below. Where the answer is "no," it says no. - **Does a security-specific incident-response runbook exist?** Resolved: **yes, and it did not when this document was first written.** - [`security-response.md`](https://github.com/hivecommons/hive/blob/v4/src/docs/security-response.md) + [`security-response.md`](https://github.com/hivecommons/hive/blob/v5/src/docs/security-response.md) documents who responds (the Maintainer Committee, which *is* the security team), how a report is triaged, and how disclosure is coordinated. It is distinct from the operational `HUB_DISASTER_RECOVERY.md`. Still missing: a @@ -974,7 +978,7 @@ repository and answered below. Where the answer is "no," it says no. honest answer was **no**: no red-team exercise and no measured detection rate for `ioscan` existed anywhere in the repository. That gap was tracked in [#6685](https://github.com/hivecommons/hive/issues/6685) and closed by - [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v4/src/docs/ioscan-red-team.md): a 43-payload adversarial corpus + [ioscan-red-team.md](https://github.com/hivecommons/hive/blob/v5/src/docs/ioscan-red-team.md): a 43-payload adversarial corpus whose result (42% withheld, 58% reached the agent) is quoted above and whose containment claim is verified in CI. What still has **not** occurred is an *external* review: no third-party audit or penetration test, and the @@ -982,7 +986,7 @@ repository and answered below. Where the answer is "no," it says no. `ioscan` in this document are now measured rather than asserted, but measured by the people who built it. -- **Will CODEOWNERS enforcement be enabled?** Resolved: the live `v4` branch +- **Will CODEOWNERS enforcement be enabled?** Resolved: the live `v5` branch protection currently requires **no** pull-request reviews at all, and enforcement was blocked on the fact that the project's own automation merges green PRs. The intended resolution is scoped enforcement over