Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXCV · Incident: Compromised RunnerIncidentResponse

Determine artifact impact — what artifacts did the runner produce, and which are suspect

Advanced⏱ ~26 mingitkubectl

What you'll learn

  • Build the artifact inventory from the runner's job history, not from the artifact registry metadata alone
  • Trace each artifact produced by the compromised runner back to the workflow run and the commit
  • Apply the decision rule: any artifact produced by the compromised runner in the compromise window is suspect
  • Distinguish artifact invalidation (mark as compromised) from artifact deletion (remove from registry) and pick the right one

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

A compromised runner has produced artifacts. Every artifact the runner touched in the compromise window is suspect: a container image with a backdoored binary, a Terraform plan that exfiltrates state, a signed attestation whose signature is now meaningless. The inventory is built from the runner’s job history, traced through the artifact registry, and used to scope the rebuild in the next lesson.

The artifact classes

A runner at runtime produces five classes of artifact:

flowchart LR
    A["compromised runner"] --> B["container images"]
    A --> C["build artifacts"]
    A --> D["Terraform plans"]
    A --> E["SBOMs"]
    A --> F["signed attestations"]
    B --> G["registry scope"]
    C --> H["artifact store scope"]
    D --> I["state backend scope"]
    E --> J["compliance scope"]
    F --> K["trust scope"]
  • Container images. Pushed to the container registry during docker build and docker push steps. The image digest is the artefact consumers reference.
  • Build artifacts. Uploaded to the workflow artifact store during actions/upload-artifact steps. Used by downstream jobs and release pipelines.
  • Terraform plans. Stored in the Terraform state backend or in a plan file artifact. Drives subsequent applies.
  • SBOMs. Generated by the build step and uploaded for compliance. The SBOM describes a binary whose integrity is now in question.
  • Signed attestations. Cosign signatures, in-toto attestations, SLSA provenance. The signature was made by a key the runner held; the signature is now meaningless.

Building the artifact inventory

The inventory is built from two sources and reconciled:

# Source 1: the runner's job history from the platform API.
# Runs are not attributed to runners — the `actor` filter selects
# the triggering USER, never the runner. Runner attribution lives
# on job objects: enumerate run ids, then filter each run's jobs
# by runner_name.
gh api --paginate /repos/OWNER/REPO/actions/runs \
  --jq '.workflow_runs[].id' > run-ids.txt

while IFS= read -r RUN_ID; do
  gh api "/repos/OWNER/REPO/actions/runs/$RUN_ID/jobs" \
    --jq '.jobs[] | select(.runner_name=="runner-prod-7c4")'
done < run-ids.txt > runner-jobs-$(date -u +%FT%TZ).json

# Source 2: the artifact registry metadata
gh api \
  /orgs/ORG/packages/container/IMAGE/versions \
  > registry-versions-$(date -u +%FT%TZ).json

The reconciliation is the cross-reference: every job in the runner’s history that produced an artifact must match a version in the registry, and every registry version that landed during the compromise window must map to a job on the compromised runner. A mismatch indicates the attacker pushed an artifact that the runner’s job history does not account for — the highest-priority finding.

The decision rule

Every artifact produced by the compromised runner in the compromise window is suspect. The window starts at the earliest moment the attacker could have used the runner (typically the runner’s registration time, or the time of the first suspicious network connection observed in the egress IDS) and ends at the moment the runner was stopped.

The rule is unconditional: a job that ran successfully on the runner before the attacker gained access is not a job that produced a trustworthy artifact, because the runner’s state from that job may have been the attacker’s foothold. The compromise window is the conservative window.

Invalidation versus deletion

For each artifact, the team chooses between invalidation and deletion:

  • Invalidation marks the artifact as compromised in the registry. Consumers see a warning when they pull. The artifact bytes remain in the registry for forensic analysis. This is the default for container images that may still be running in production.
  • Deletion removes the artifact bytes from the registry. Consumers fail when they pull. This is the default for build artifacts that have already been consumed and for images that have been confirmed backdoored.
Artifact classDefault actionRationale
Container images still runningInvalidateProduction must roll forward, not back
Container images confirmed backdooredDeleteThe backdoor is documented; deletion is safe
Build artifactsArchive (offline)Required for forensic analysis
Terraform plansInvalidatePlans are reference documents, not consumed bytes
SBOMsInvalidateThe SBOM describes a suspect binary
Signed attestationsRevokeThe signature is now meaningless

Production discipline

  1. Inventory before action. The artifact inventory drives the rebuild scope; missing an artifact means missing a backdoor.
  2. Conservative window. The compromise window starts at the earliest possible moment, not the latest.
  3. Invalidate by default. Destructive actions are reserved for confirmed-backdoored artifacts.
  4. Reconcile the two sources. The runner’s job history and the registry metadata must agree on every artifact.

Cross-course references

  • Linux for Production Sysadmins - Part XXXII (ContainerImages) covers the registry deletion patterns that the deletion action requires.
  • Kubernetes for Production Sysadmins - Part XXIII (ImageSupplyChain) covers the image admission policies that the invalidation warning triggers.
  • Terraform for Production Sysadmins - Part XV (CredentialRotation) covers the Terraform plan artifact class.

Quiz

Knowledge check · 4 questions

  1. Q1. The artifact registry contains a container image digest that does not match any workflow run on the compromised runner. What is the right interpretation?

  2. Q2. A container image produced by the compromised runner before the attacker gained access is not safe to leave in the registry without invalidation.

  3. Q3. Name the two sources used to build the artifact inventory and state what a mismatch between them indicates.

  4. Q4. A runner pod has run 47 jobs in the compromise window. The job history shows 47 workflow runs. The registry shows 52 container image versions in the same window. Triage the mismatch.

    The runner pod held GITHUB_TOKEN, an AWS access key, and a registry push token. The job history comes from the platform API. The registry metadata comes from the container registry API. The five extra image versions do not map to any of the 47 workflow runs.

Passing score: 75%. Answers are checked in this browser.