On October 9, The Hacker News reported a new wave of the GhostAction supply chain campaign. Attackers used stolen maintainer credentials, most likely leaked tokens, to push a fake "security audit" workflow straight to default branches. The workflow harvested repository secrets and keys buried in git history. It sent them to a hard-coded server. Socket counted more than 500 affected accounts since October 7.
Now picture a NIST SP 800-218 compliance questionnaire landing that same week. It asks whether your build environments are isolated. It asks how you track provenance and which tools check for vulnerabilities. Someone at your company has to sign the answers.
The Signature Outlived the Mandate
In January, the White House budget office issued OMB memo M-26-05. It rescinded the memos that made the CISA common attestation form mandatory for federal software. That sounds like relief. Keep reading.
Agencies now set their own risk-based requirements. They may keep using the common form. They may write contract terms that demand a current SBOM on request. The memo points them to the Secure Software Development Framework (SSDF). In Cybersecurity Dive's coverage, experts warned that agency-by-agency requirements could raise the burden on vendors. Enterprise security reviews ask the same questions in their own formats.
So the form did not vanish. It multiplied.
The stakes did not shrink either. The common form is signed by the CEO or a designee who can bind the company. It warns that willfully false statements can violate 18 U.S.C. 1001, a criminal statute. An enterprise questionnaire becomes a contract representation. Either way, a signature turns pipeline settings into legal claims.
The form's four claims are a fair summary of what most reviewers want:
- Software is built in secure, separated environments.
- The source code supply chain is protected in good faith.
- Provenance is kept for internal code and third-party components.
- Automated tools check for vulnerabilities before release, backed by a disclosure program.
That makes this an engineering problem, not a paperwork problem. Every answer should point to a log, a ruleset, a signature or an SBOM that already exists.
Protect the Software (PS): Harden the Forge
In NIST SP 800-218, practice PS.1 protects all code from unauthorized access and tampering. Practice PO.5 covers the build environments themselves. Version 1.1 remains final while NIST works through a 1.2 draft released in December 2025. GhostAction walked through three seams: a long-lived token, an unguarded default branch and secrets parked in CI settings. Close each one.
1. Scope every token to the job. Set the default workflow token to read-only. Grant extra permissions per job. Use fine-grained personal access tokens with short expiry dates. A token without the workflow permission cannot push new workflow code, and one without admin rights cannot delete your rulesets. Replace stored cloud keys with OIDC, so each job receives a credential that expires on its own.
permissions:
contents: read # every job starts read-only
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # required reviewers
permissions:
contents: read
id-token: write # short-lived OIDC credential
On the cloud side, trust only this repository and this environment. Keep any remaining secrets at the environment level, and limit deployments to the default branch. A planted workflow then stalls at the approval gate, where a person makes the call. Turn on prevent self-review. On private repositories, required reviewers need GitHub Enterprise; on other plans, deployment branch rules carry the load.
2. Make runners disposable. Every job should get a fresh machine that is destroyed afterward. Then no cached credentials or planted binaries survive to poison the next build. Hosted runners already work this way. On self-hosted runners, the ephemeral flag de-registers a runner after one job. Your automation, or Actions Runner Controller on Kubernetes, then tears the machine down.
./config.sh --url https://github.com/your-org \
--token <registration-token> --ephemeral
3. Lock the default branch and sign commits. Add a ruleset that requires a reviewed pull request and passing status checks. Block force pushes and require signed commits. Keep the bypass list empty. A direct push to the default branch then gets refused. GhostAction's workflow also fires on pushes to any other branch, which is why secrets belong in branch-restricted environments. Where your plan supports push rulesets, restrict who can change .github/workflows. Git has supported SSH signing since version 2.34:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
Signing proves which key made a commit. Review proves a second person looked. You need both.

Produce Well-Secured Software (PW): Gates Without Friction
Practice PW.4 covers third-party components. PW.7 covers code review and analysis, and PW.8 covers testing the running build. Scanners create friction when every tool runs on every commit and fails on old debt. Put each check where it is cheapest:
- Laptop: a pre-commit secrets scan. It takes seconds, before anything leaves the machine.
- Pull request: SAST with Semgrep or CodeQL, plus SCA on changed manifests. Block only new high and critical findings.
- Main branch, nightly: full SAST and dependency scans. Old findings go to the backlog, not the merge button.
- Staging: a DAST baseline scan against the deployed preview. The ZAP baseline is passive and finishes in minutes. Run active scans weekly.
docker run -t ghcr.io/zaproxy/zaproxy:stable \
zap-baseline.py -t https://staging.example.com
The gates handle the repetitive checks. Reviewers keep their attention for design flaws and the exceptions no scanner can judge.
Gates should also fail closed. In our release engineering case study, a deploy that cannot prove its new process started fails on purpose. The old version keeps serving. Security gates deserve the same rule.
Secrets never enter the repository. Start with a hook:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.2 # pin it, let your bot bump it
hooks:
- id: gitleaks
Hooks can be skipped, so run the same scan in CI. Then run gitleaks git once across the full history, because GhostAction harvested keys from history too. At runtime, the job pulls credentials from your vault or cloud provider through OIDC. Nothing lives in the repository, and nothing outlives the job.

The SBOM: Release Evidence for NIST SP 800-218 Compliance
SSDF task PS.3.2 asks you to collect, protect and share provenance data for every release. A software bill of materials is the standard vehicle. CISA's 2026 Minimum Elements for an SBOM, released in July, added component hash, license, tool name and generation context to the baseline.
Two formats dominate:
- SPDX comes from the Linux Foundation and is standardized as ISO/IEC 5962:2021. It grew out of license compliance. Version 3.0 added security and build profiles.
- CycloneDX comes from OWASP and is standardized as ECMA-424. It grew out of security work and supports VEX and service inventories natively.
Most generators emit both. Pick the one your buyers ask for.
Generate the SBOM at release, from the built artifact rather than the source tree. Scanning the image catches OS packages, transitive dependencies and every container layer:
syft scan registry.example.com/app@sha256:<digest> \
--scope all-layers -o cyclonedx-json=sbom.cdx.json
cosign sign --yes registry.example.com/app@sha256:<digest>
cosign attest --yes --type cyclonedx \
--predicate sbom.cdx.json registry.example.com/app@sha256:<digest>
Run these in the release job, after tests pass and before the image is promoted. If you build with Docker BuildKit, the --sbom=true and --provenance=mode=max flags attach similar evidence at build time.
Sign by digest, never by tag. Tags move. Archive the SBOM with each release, then scan it daily against vulnerability feeds. An SBOM nobody reads is a receipt, not a control.

Compliance as a Competitive Moat
Fragmented requirements reward the vendor who can answer any format quickly. When the evidence already exists, a new questionnaire becomes an afternoon of linking artifacts. Rulesets, OIDC trust policies, scan history and signed SBOMs answer most SSDF questions directly. Procurement moves faster when every answer arrives with proof. The vendor still reconstructing its pipeline from memory loses weeks.
Keep an evidence folder for every release: the ruleset export, the trust policy, the scan results and the signed SBOM. Sales can hand it over the day a questionnaire arrives. Security stops being the reason a deal stalls.
Run This Check Before You Sign
Audit the pipeline before the next questionnaire does it for you. Give it one hour this week:
- Count long-lived secrets in your CI settings. Each should become an OIDC role or an environment secret.
- Test both GhostAction paths. Try a direct push to your default branch. Then push a harmless workflow to a new branch and check which secrets it can reach. If either works, the path is open.
- Check your last build's runner. If it served earlier jobs, it is not ephemeral.
- Pull the SBOM for your last release. If it is missing, PS.3.2 is unanswered. If it was built from source, it is only partly answered.
- Find your oldest open high-severity finding. Its age is your real remediation policy.
- Open your vulnerability disclosure page. If outside researchers cannot reach you, the form's fourth claim is unsupported.
If any answer is "not sure," hold the signature.
Our custom software application work covers the pipeline as well as the product. If your check turns up gaps, we can build these gates into the pipeline you already run. We scope it as a fixed price, quoted up front.


