GitHub Actions
import { Aside, Steps } from ‘@astrojs/starlight/components’;
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.
Quickstart
Section titled “Quickstart”Drop this into .github/workflows/secret-scan.yml:
name: secret-scanon: [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: highFor the <40-char-sha> pin value, copy the latest commit SHA from the opaquev/ov-scan-action releases page.
What it does
Section titled “What it does”When the action runs in your CI, it:
- Downloads
ovfromreleases.opaquevault.comfor the runner’s platform. - Verifies the binary against a minisign signature using a vendored verifier — no
go install, no third-party action proxies. - Runs
ov scanagainst your repository checkout. - Emits findings counts via the action’s outputs, fails the job per your
fail-onthreshold.
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.
Pin to SHA, not tag
Section titled “Pin to SHA, not tag”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 pinuses: opaquev/ov-scan-action@<40-char-sha>
# ❌ DON'T — tag pin in productionuses: opaquev/ov-scan-action@v1Inputs
Section titled “Inputs”| Input | Default | Description |
|---|---|---|
path | . | Path to scan (relative to repo root). Allowlist regex; no .. segments, no absolute paths. |
baseline-file | .ovscan-baseline.txt | Path to baseline file with HMAC-fingerprinted accepted findings. |
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 | 1048576 | Memory budget in KB (Linux only; macOS no-op per ulimit -v semantics). |
Outputs
Section titled “Outputs”| 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. |
Supported runners
Section titled “Supported runners”| 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. |
pull_request_target hardening
Section titled “pull_request_target hardening”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 misconfigurationon: pull_request_targetjobs: 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 gateIf 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.
Updating
Section titled “Updating”The action follows GitHub’s standard versioning conventions. To upgrade:
- Recommended (SHA-pin): bump the pinned commit SHA in your workflow file. Dependabot’s
actionsecosystem will open these PRs automatically when configured. - Tag-pin (not recommended for production): if you’ve used
@v1, you’ll get the latestv1.x.yautomatically — at the cost of trusting that no compromise lands onmainbetween releases.
Each release ships:
- An immutable
v1.x.ytag - A floating
v1tag updated to point at the latestv1.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 shell-script wrapper does the same signature verification work the action does for GH Actions. |
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.
Security model
Section titled “Security model”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 -ienv-strip —ov scanis 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_VERSIONruns before customer-supplied bounds. - Fork-PR strict mode — refuses
allow-binary-version,allow-ci-baseline,max-ov-versionoverrides on fork-PR runs (non-overridable).
For vulnerability reports, see opaquev/ov-scan-action/SECURITY.md.
See also
Section titled “See also”ov scan— the underlying scanner CLIov --check-version-bounds— semver gate the action uses- Action repo — source, releases, advisories