OWASP SPVS Coverage
Overview
Section titled “Overview”The OWASP Software Provenance Verification Standard (SPVS) 1.6 is a supply-chain control catalog for how software is identified, built, signed, published, and monitored. You may also see it abbreviated as OSVS; the official name is SPVS. It is not the same standard as OWASP SCVS.
Fencer covers the GitHub-reachable subset of SPVS 1.6 across three surfaces:
- GitHub SaaS checks — organization, repository, workflow, dependency, and release posture evaluated through the GitHub App. Findings are Vulnerabilities on the GitHub SaaS Account asset.
- OpenGrep GitHub Actions rules — static analysis of workflow YAML during code scans. Findings are Vulnerabilities on the repository.
- SIEM detections — GitHub audit and webhook events matched by built-in detection rules.
SPVS 1.6 defines 50 requirements. 37 of those can be assessed from GitHub APIs, repository contents, and GitHub audit events without an endpoint agent or live admission control. Fencer’s target for that GitHub-reachable set is 36 of 37 Covered. One requirement is excluded by design. Five others can only ever be Partial because GitHub or Fencer cannot observe the remaining half of the control. Remaining gaps are listed under Planned coverage.
Prerequisites
Section titled “Prerequisites”- A connected GitHub App Code installation, with repositories imported as assets.
- SaaS Scanning for organization and repository posture checks.
- Code Scanning for OpenGrep GitHub Actions rules.
- Security Monitoring with the GitHub Monitor app for provenance detections (package publish and workflow configuration change).
Coverage policy
Section titled “Coverage policy”| Status | Meaning |
|---|---|
| Covered | Fencer raises a Vulnerability or Detection when the GitHub-visible control fails |
| Partial by design | Fencer covers the observable half; the rest is not visible via GitHub APIs or Fencer’s role |
| Not covered by design | Deliberately out of scope (would expand GitHub App install-time trust) |
| Planned | Reachable on GitHub, not yet shipped |
Identity and access (V1)
Section titled “Identity and access (V1)”Default repository permission (High, SaaS) — Organization default_repository_permission must
be none. Member read, write, or admin access to every repository by default fails SPVS
V1.1.3.
Unsigned commits on the default branch (High, SaaS) — Recent default-branch commits must have verified signatures. If you configure an approved signer list, verified commits from anyone else also fail (SPVS V1.4.1). An empty allowlist treats any verified signer as acceptable.
Also covered on this section’s GitHub surface: organization 2FA enforcement, privileged role minimization, GitHub App token minting, fine-grained PATs for automation, dedicated bot accounts, environment reviewers, deployment branch restriction, and custom protection rules.
Partial by design — phishing-resistant MFA (V1.1.1). GitHub’s API reports whether 2FA is on, not whether the factor is phishing-resistant. Fencer can require 2FA; it cannot distinguish TOTP from a hardware key.
Dependencies (V2)
Section titled “Dependencies (V2)”Lockfile drift (Medium, SaaS) — The lockfile must satisfy the manifest’s declared ranges (SPVS V2.2.3). Fencer compares these pairs when both files are present:
| Language | Manifest | Lockfile |
|---|---|---|
| JavaScript / TypeScript | package.json | package-lock.json, pnpm-lock.yaml, yarn.lock, or bun.lock |
| Python | pyproject.toml | uv.lock |
| Ruby | Gemfile | Gemfile.lock |
| Go | go.mod | go.sum |
| Rust | Cargo.toml | Cargo.lock |
| Java | pom.xml, build.gradle, or build.gradle.kts | gradle.lockfile |
| C# | .csproj, Directory.Packages.props, or packages.config | packages.lock.json |
| PHP | composer.json | composer.lock |
| Dart | pubspec.yaml | pubspec.lock |
| Swift | Package.swift | Package.resolved |
| Elixir | mix.exs | mix.lock |
Platform packages, git/path sources, and unpinned branch/revision constraints are skipped. Composer
php / ext-* / lib-* packages, Dart SDK/git/path deps, Swift branch/revision/path deps, and Mix
git/path/GitHub deps are not compared.
Direct public registry installs (OpenGrep) — CI run: steps that install from a known public
host (npmjs.org, pypi.org, rubygems.org, crates.io, proxy.golang.org, nuget.org, packagist.org,
Maven Central, pub.dev, hex.pm, and similar) or omit a private --registry / --index-url /
GOPROXY override fail SPVS V2.2.6.
Install scripts enabled (OpenGrep) — npm/yarn/pnpm/bun without --ignore-scripts, Composer
without --no-scripts, and pip with --no-build-isolation fail SPVS V2.2.1. This sits alongside
the existing Dependabot insecure-external-code-execution rule; it does not replace it.
Also covered: binary blob dependencies, and OpenGrep rules for Dependabot insecure external code execution, dependency cooldowns, Cargo feature minimization, and installer checksum verification.
Partial by design — local env-file secrets (V2.1.1). Workstation filesystem secrets are outside GitHub’s API and Fencer’s GitHub App scope.
Build and CI (V3)
Section titled “Build and CI (V3)”Floating package installs (OpenGrep) — Workflow run: steps that install floating versions fail
SPVS V3.1.1. Lockfile-exact commands pass, including npm ci, yarn/pnpm/bun --frozen-lockfile,
pip install --require-hashes, uv sync --frozen, bundle install --frozen, cargo build --locked, composer install, dotnet restore --locked-mode, dart pub get, and mix deps.get.
Self-hosted runners (Critical on public, Informational on private, SaaS) — Jobs with runs-on: self-hosted (or a runner group) fail SPVS V3.1.6’s GitHub-visible half. Public repositories are
Critical because pull requests can execute untrusted code on organization-managed machines.
Static registry credentials with OIDC (OpenGrep) — Workflows that grant id-token: write and
still interpolate a static registry token (NPM_TOKEN, PYPI_TOKEN, CARGO_REGISTRY_TOKEN,
NUGET_API_KEY, PACKAGIST_TOKEN, MAVEN_CENTRAL_TOKEN, and similar) fail SPVS V3.2.3. Existing
missing-OIDC rules are unchanged.
Reusable workflow secret overshare (High, SaaS) — Named secrets passed into a reusable workflow
must be declared under the callee’s on.workflow_call.secrets. Extra names fail SPVS V3.2.1.
secrets: inherit is handled by a separate OpenGrep rule, not this check.
Whole credential context exposure (OpenGrep) — Passing the whole secrets context into a
reusable workflow or action also fails SPVS V3.2.1.
Sigstore untrusted builder (High, SaaS) — When attestations exist, the SLSA builder identity must match an accepted prefix (GitHub-hosted runner, GitHub artifact-attestations workflows, or SLSA GitHub generator by default). Unparseable builder IDs fail closed (SPVS V3.4.6).
Also covered on this section: default Actions permissions, Actions execution policy, dangerous
triggers, job permission minimization, impostor commits, mutable binary downloads, stale Action
pins, archived Actions, caching in public release jobs, secrets scoped to environments, long-lived
registry credentials, Sigstore attestation presence, unpinned Actions and container images, missing
OIDC trusted publishing, GITHUB_ENV / GITHUB_PATH injection, spoofable actor conditions, unsound
if: expressions, typosquatted action names, actions/checkout persist-credentials, and missing
release code signing.
Partial by design — runner re-imaging (V3.1.6). Whether a persistent self-hosted runner is re-imaged and scanned is infrastructure state with no GitHub API. Fencer flags use of self-hosted runners; it cannot verify the host image.
Partial by design — consumers validate (V3.4.2). Downstream verification in another organization or repository is generally not visible to this GitHub App installation.
Not covered by design — org-wide secret visibility (V3.2.2). Confirming that secrets are not
scoped to the whole organization or all repositories requires the organization_secrets / secrets
GitHub App permission. Fencer does not request that permission and does not expand install-time
trust to get it.
Publish (V4)
Section titled “Publish (V4)”Covered on GitHub: organization and repository tag rulesets, tag immutability, immutable releases, tag creation gated on deployment, and admin bypass of organization rulesets.
Detect and respond (V5)
Section titled “Detect and respond (V5)”GitHub Package Publish (Medium, SIEM) — Detects GitHub release publishes, package registry publishes, and pushes of git tags so unexpected publishes can be investigated before they are trusted (SPVS V5.2.4).
GitHub Workflow Configuration Change (Medium, SIEM) — Detects changes to .github/workflows
files and enable/disable of workflows, including the acting identity (SPVS V5.2.6).
Also covered: GitHub push protection disabled, repository ruleset change, tag modification, webhook created, and webhook configuration change. See Detection Rules.
Partial by design — validated before deploy (V5.1.1). Fencer can alert after a deployment. It has no admission-control mechanism to block a deploy that lacks a validated SBOM.
Planned coverage
Section titled “Planned coverage”These GitHub-reachable requirements are not Covered yet:
- Screening new packages for install scripts, maintainer count, age, and linked source before first use
- Integrity-checking security-scanner invocations in CI
- Diffing published release artifacts against pipeline build output
- Verifying the previous stage’s artifact signature between pipeline jobs
- Documented break-glass (with alert and review) for signature or attestation bypass
- Publish blast-radius: one identity releasing a second package inside a cooldown without extra approval
- Fuzzy typosquat screening of popular Actions and package names
- Detecting release jobs that rebuild instead of consuming a held artifact
- Checksum verification after cache restore in release-adjacent jobs
- Resolving transitive GitHub Action dependencies and flagging unpinned refs
- Alerting when a production deployment has no matching SBOM
- Tightening app-token and PAT checks toward one-credential-one-resource isolation
- Requiring reviewers, branch restriction, and custom protection together on release environments