Skip to content

GitHub Actions

The official opaquev/ov-scan-action drops ov scan into your GitHub Actions pipeline. It downloads a signed ov binary, verifies the signature against a vendored minisign trust root, and runs the scanner against your checkout — all without touching the network for scan content. It’s listed on the GitHub Marketplace.


Drop this into .github/workflows/secret-scan.yml:

name: secret-scan
on: [pull_request]
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: opaquev/ov-scan-action@<40-char-sha> # see "Pin to SHA" below
with:
path: .
fail-on: high

For the <40-char-sha> pin value, copy the latest commit SHA from the opaquev/ov-scan-action releases page.


When the action runs in your CI, it:

  1. Downloads ov from releases.opaquevault.com for the runner’s platform.
  2. Verifies the binary against a minisign signature using a vendored verifier — no go install, no third-party action proxies.
  3. Runs ov scan against your repository checkout.
  4. Emits findings counts via the action’s outputs, fails the job per your fail-on threshold.

The action is load-bearing trusted code, so it shipped after 6 rounds of pre-implementation security review catching 35+ findings, plus another ~15 implementation-time defects fixed during PR review.


Production users must pin to a commit SHA: uses: opaquev/ov-scan-action@<40-char-sha>.

The @v1 tag is informational only. Pinning to a tag means a maintainer (or a compromise of the action repo) can ship a malicious update that you consume on the next CI run. SHA pinning + Dependabot’s actions ecosystem gives you reviewable, auditable bumps.

# ✅ DO — SHA pin
uses: opaquev/ov-scan-action@<40-char-sha>
# ❌ DON'T — tag pin in production
uses: opaquev/ov-scan-action@v1

Defaults below are as of v1.0.3. If you pin to an older release SHA (as the pinning guidance recommends for production), check that release’s own README — notably, memory-budget defaulted to 1 GiB until v1.0.2 raised it to 4 GiB (v1.0.1 still ships the 1 GiB default).

Input Default Description
path . Path to scan (relative to repo root). Allowlist regex; no .. segments, no absolute paths.
baseline-file '' Path to baseline file with HMAC-fingerprinted accepted findings. Empty (default) skips baseline; the action passes --baseline only if explicitly set.
fail-on high Severity threshold: verified|critical|high|medium|low|info.
min-ov-version '' Minimum ov binary version (e.g., v0.10.0). Customer floor; cannot loosen the action’s embedded OV_VERSION floor.
max-ov-version '' Maximum ov binary version.
allow-pull-request-target false DANGEROUS — see pwn-request hardening below.
allow-binary-version false Override binary version (refused on fork PRs).
allow-ci-baseline false Allow baseline modifications in CI (refused on fork PRs).
time-budget 300 Wallclock seconds for ov scan invocation.
memory-budget 4194304 Memory budget in KB (Linux only; macOS no-op per ulimit -v semantics). Default 4 GiB — do not set below ~2 GiB: the Go runtime needs that much virtual address space on linux_arm64 and segfaults under a lower cap (OV-256).
Output Description
findings-count Total findings (includes baselined; subtract baselined-count for unbaselined-only).
baselined-count Findings suppressed by baseline.
verified-count Findings whose liveness was verified.

Runner Status Notes
ubuntu-latest (linux_amd64) ✅ supported
Linux ARM64 (linux_arm64) ✅ supported self-hosted ARM runners
macos-latest / macos-14+ (darwin_arm64) ✅ supported
macos-13 (darwin_amd64, Intel) not supported jedisct1’s signed minisign 0.12 macOS release is arm64-only Mach-O; we don’t ship a self-built darwin_amd64 binary because it would weaken the supply-chain trust chain. macOS 13 is deprecated by GitHub anyway; migrate to macos-14+ (arm64).
windows-latest ❌ not yet tracked under OV-245.

By default the action refuses to run under pull_request_target. This is the most dangerous workflow trigger in GitHub Actions: it runs in the base repo’s context with base-repo secrets, but a malicious PR author can influence what the workflow does.

The combination most users get wrong:

# ❌ DON'T — CVE-class misconfiguration
on: pull_request_target
jobs:
scan:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # ← attacker-controlled checkout
- uses: opaquev/ov-scan-action@<sha>
with:
allow-pull-request-target: true # ← unlocks the gate

If you set allow-pull-request-target: true AND check out the PR head ref, you’ve created a fork-PR-controlled execution path with access to your base-repo GITHUB_TOKEN. A malicious PR’s hooks/scripts/dependencies can exfiltrate the token. See the GitHub Security Lab “pwn requests” writeup.

The action emits a ::warning:: whenever allow-pull-request-target=true is honored. If you see that warning in production CI, double-check your actions/checkout step.


The action follows GitHub’s standard versioning conventions. To upgrade:

  1. Recommended (SHA-pin): bump the pinned commit SHA in your workflow file. Dependabot’s actions ecosystem will open these PRs automatically when configured.
  2. Tag-pin (not recommended for production): if you’ve used @v1, you’ll get the latest v1.x.y automatically — at the cost of trusting that no compromise lands on main between releases.

Each release ships:

  • An immutable v1.x.y tag
  • A floating v1 tag updated to point at the latest v1.x.y
  • A GitHub Release with full changelog

Customers running self-hosted GitHub Enterprise: the action is a composite action (no Docker image). Mirror the repo into your enterprise’s actions/ cache or use the published tags directly.


Action vs. CLI install — when to use which

Section titled “Action vs. CLI install — when to use which”
Surface Use
GitHub Actions CI Use opaquev/ov-scan-action. It bundles signature verification + platform selection + fail-closed parsing.
Local development Install ov directly: curl https://get.opaquevault.com | sh. See installation.
Other CI systems (GitLab, CircleCI, etc.) Install ov directly in your pipeline: curl https://get.opaquevault.com | sh, then run ov scan. The install script verifies the minisign signature only when minisign is installed on the runner; otherwise it falls back to SHA-256 only and prints a warning. Install minisign in the job and set OV_REQUIRE_SIGNATURE=1 so the install fails closed — see Release signing.

The action is specifically for GitHub Actions because it leverages the composite-action surface (inputs, outputs, env-binding) for workflow-injection prevention. Other CI systems should call ov scan directly via the install script.


The action’s full threat model is documented at opaquev/ov-scan-action/docs/threat-model.md. Key defenses:

  • Vendored minisign verifier — no runtime go install, no third-party CDN trust beyond the binary CDN itself.
  • Same-UID swap defense(inode, mtime, size) stat-snapshot + recheck before every consumer use of every trust-root file.
  • exec env -i env-stripov scan is launched with a clean environment; GITHUB_TOKEN, *_KEY, *_SECRET, LD_PRELOAD, etc. are stripped.
  • Stale-checksums replay defeated — unconditional version-floor check against the action’s embedded OV_VERSION runs before customer-supplied bounds.
  • Fork-PR strict mode — refuses allow-binary-version, allow-ci-baseline, max-ov-version overrides on fork-PR runs (non-overridable).

For vulnerability reports, see opaquev/ov-scan-action/SECURITY.md. Published advisories — including GHSA-59j2-rc8j-4q5w (the v1.0.0 baseline auto-load issue described above) — are recorded with verification steps on the security advisories page.