Skip to content

[EPIC] Fork hardening wave 1: red-team remediation (2026-07-25) #15

Description

@smsmatt

Adversarial assessment of Sanmarcsoft/headroom run 2026-07-25 by six parallel red-team agents across six disjoint attack surfaces (CI supply chain, proxy network surface, credential handling, code-execution surfaces, fork governance, egress and telemetry). Every finding below cites file:line or a live API probe. This epic tracks remediation; it fixes nothing on its own.

The state of the fork, measured

$ git rev-list --count upstream/main..HEAD   # commits ahead
0
$ git rev-list --count HEAD..upstream/main   # commits behind
9
$ git grep -il sanmarcsoft                   # SanMarcSoft-specific content
(nothing)

Zero local commits. No charter, no AGENTS.md, no ISA.md. REALIGNMENT/ is upstream's own document, not ours. Upstream ships roughly 20 commits per day.

The one finding that matters most

The mirror is publishing cosign-signed container images of code nobody here has reviewed.

.github/workflows/docker.yml fires on every push to main (line 4), derives the image name from github.repository (line 122), pushes unconditionally (push: true, line 132), and signs the multi-arch index with keyless Sigstore OIDC (lines 354-381). Because syncing upstream means pushing to main, each sync publishes to ghcr.io/sanmarcsoft/headroom under SanMarcSoft's own signing identity.

This already happened. Run 30155106724, Docker, main, push, succeeded in 11m32s on 2026-07-25.

An organisation whose business is content provenance is currently attesting to third-party code it has not read. That is the finding that reframes the rest.

Severity roll-up

# Severity Finding Surface
#1 CRITICAL Mirror publishes cosign-signed GHCR images of unreviewed code CI
#2 CRITICAL RCE via trust_remote_code=True on a request-supplied model string code exec
#3 HIGH SSRF via unconditional x-headroom-base-url proxy
#4 HIGH Unauthenticated data plane on the default docker-compose bind proxy
#5 HIGH headroom wrap Docker path publishes the port on all interfaces code exec
#6 HIGH Unpinned, unverified remotely-fetched executables at runtime supply chain
#7 HIGH CI actions unpinned, gitleaks unverified, token scopes missing CI
#8 HIGH Credential and memory at-rest hardening gaps credentials
#9 HIGH Egress and data-sovereignty audit outstanding egress
#10 HIGH The fork has no declared purpose governance
#11 HIGH Inherited automation runs unattended on the mirror governance
#12 MEDIUM GitHub security features are switched off platform
#13 MEDIUM No sync cadence, no drift alerting, no branch protection governance
#14 MEDIUM Upstream disclosure decision outstanding governance

Convergent findings, reached independently by three or more agents: unverified code fetched from mutable remote references and then executed (#2, #6, #7, and the CDN half of #9), and live automation on an unowned mirror (#1, #11, #13).

Steelman: why holding this fork is defensible

  1. Zero local commits means every upstream fix is a pure fast-forward, the cheapest state a fork can hold.
  2. Upstream governance is genuinely strong: SECURITY.md, gitleaks and gitguardian scanning, cosign-signed images, release-please.
  3. A fork gives an independent copy if upstream disappears, is acquired, or relicenses.
  4. The inherited REALIGNMENT/ documents are upstream's own admission of architecture debt, free due diligence.
  5. Holding the code locally is what made this assessment possible at all; a dependency pin would not have.
  6. An LLM proxy in the request path is strategically interesting for a provenance business, worth understanding deeply.
  7. The security posture found here is above average for self-hosted proxies: loopback guards, strict TLS defaults, opt-in prompt logging.
  8. Nothing here is broken today, and the cost of holding the option open is close to zero.

Counter-argument: why that is not enough

  1. A fork nobody has declared a purpose for is a bookmark carrying liabilities, not an asset.
  2. The option is not free: it publishes signed images and burns CI minutes on every sync.
  3. Signing unreviewed third-party code with our identity inverts the exact value the business sells.
  4. "Zero local commits" is a snapshot, not a property; the first patch converts it into permanent merge work.
  5. Twenty upstream commits a day means the mirror silently drifts out of security parity, not just feature parity.
  6. The build path violates the standing Nix and Scaleway-registry SOP; nobody has decided whether that is an accepted exception.
  7. Reading the code required no fork; a shallow clone would have produced this same assessment.
  8. Every technical finding here is upstream's bug. The only findings that are genuinely ours are the governance ones, and those are unowned.

Remediation checklist

Sequencing

Stop the bleeding first: #1 and #11 are configuration changes that close the active exposure within minutes and cost nothing.

Then decide: #10 is the root cause. Every remaining item is scoped differently depending on whether this fork is kept or retired. If it is retired, #2 through #9 collapse into #14 (tell upstream) plus a dependency pin.

Then fix: #2 through #9 in severity order, but only after #10 says the fork is ours to patch.

What this assessment deliberately did not do

Scaffolding created for this epic

GitHub Issues was disabled on this repository and was enabled to file this work. Labels (epic, security, supply-chain, ci-cd, credentials, egress, governance, fork-sync, priority:*) and the Fork Hardening Wave 1 milestone were created. Org project Headroom Fork (#12) was created as the board. Issue Type could not be set: the session token is refused issueTypes access at the org level, so type is carried as a label instead.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    epicTracking issue grouping related sub-issuesgovernanceFork strategy, ownership, and processpriority:criticalDrop everythingsecuritySecurity-relevant work

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions