{
  "generatedAt": "2026-10-12T16:01:05.493Z",
  "statsFetchedAt": "2026-10-10",
  "ratingLabels": {
    "1": "Legacy",
    "2": "Niche",
    "3": "Situational",
    "4": "Recommended",
    "5": "Top pick"
  },
  "ratingRubric": {
    "1": "Archived or deprecated. Listed for reference. Plan a migration if you still run it.",
    "2": "Mostly superseded or very narrow. Use it only if you have a specific reason.",
    "3": "Good for a specific need or as a second opinion. Smaller project or slower maintenance.",
    "4": "Worth running, with a real trade-off: more noise, narrower scope, heavier setup, or the best parts need an account.",
    "5": "The default choice for its job. Accurate, actively maintained, easy to run in CI, fully usable without a paid account."
  },
  "modelLabels": {
    "oss": "Open source",
    "open-core": "Open core",
    "oss-client": "Open client, hosted service",
    "source-available": "Source available"
  },
  "categories": [
    {
      "id": "workflows",
      "title": "Workflow analysis",
      "blurb": "Static analysis of .github/workflows and action.yml files: script injection, dangerous triggers, excessive token permissions, unpinned uses."
    },
    {
      "id": "pinning",
      "title": "Action pinning",
      "blurb": "Rewrite uses: references to full commit SHAs, keep them current, and check they still match."
    },
    {
      "id": "runtime",
      "title": "Runner hardening",
      "blurb": "Watch or restrict what a job does while it runs: outbound network, file tampering, and which token permissions it actually used."
    },
    {
      "id": "secrets",
      "title": "Secret scanning",
      "blurb": "Find credentials in code, git history, CI logs and artifacts, before or after they are pushed."
    },
    {
      "id": "vulns",
      "title": "Vulnerable dependencies",
      "blurb": "Match the packages you ship against advisory databases such as OSV.dev, the GitHub Advisory Database and the NVD."
    },
    {
      "id": "malicious",
      "title": "Malicious packages",
      "blurb": "Look at what a package does rather than whether it has a CVE: install scripts, network calls, obfuscation, typosquats, sudden maintainer changes."
    },
    {
      "id": "sast",
      "title": "Code scanning (SAST)",
      "blurb": "Pattern matching and dataflow analysis over your own source code."
    },
    {
      "id": "iac",
      "title": "IaC and container config",
      "blurb": "Misconfigurations in Terraform, Kubernetes manifests, Dockerfiles and CI config, caught before they are applied."
    },
    {
      "id": "posture",
      "title": "Org and repo posture",
      "blurb": "Check and enforce GitHub settings across an organization: branch protection, admins, 2FA, Actions policy, stale access."
    }
  ],
  "tools": [
    {
      "id": "zizmor",
      "name": "zizmor",
      "repo": "zizmorcore/zizmor",
      "category": "workflows",
      "model": "oss",
      "rating": 5,
      "ratingNote": "The most thorough open-source scanner for Actions workflows, fast, offline by default and actively released.",
      "summary": "Static analysis for GitHub Actions workflows and action.yml files, written in Rust.",
      "howItWorks": [
        "zizmor parses every workflow under .github/workflows, composite action definitions (action.yml) and Dependabot config, and runs a set of named audits over the parsed YAML. Each audit knows the semantics of Actions: which triggers run with secrets, which expression contexts an outsider controls, and what a uses: reference resolves to.",
        "Most audits are offline: template-injection, dangerous-triggers, excessive-permissions, unpinned-uses, artipacked (credentials left by actions/checkout), cache-poisoning, secrets-inherit and self-hosted-runner. Online audits such as impostor-commit, ref-confusion and known-vulnerable-actions call the GitHub API with a token to check that a pinned SHA really belongs to the action's repository and that the version has no advisory.",
        "Findings carry a severity and a confidence. Personas (regular, pedantic, auditor) control how noisy it is, a zizmor.yml file or an inline '# zizmor: ignore[audit]' comment suppresses findings, and output is plain text, JSON, SARIF or GitHub annotations."
      ],
      "catches": [
        "Attacker-controlled expressions such as PR titles inside run: steps",
        "pull_request_target and workflow_run used with a checkout of PR code",
        "Actions referenced by tag or branch instead of a full SHA",
        "Commit SHAs that only exist in a fork (impostor commits, online)",
        "Write-all or missing permissions blocks",
        "persist-credentials left on before an artifact upload"
      ],
      "run": "pipx install zizmor\nzizmor .\n# CI-friendly: no network, SARIF out\nzizmor --no-online-audits --format sarif . > zizmor.sarif",
      "network": "Offline audits send nothing. Online audits call the GitHub API with GH_TOKEN; --no-online-audits turns them off.",
      "limits": [
        "Static only. It cannot see what an action does at runtime or what a setup script downloads.",
        "Online audits need a token and count against API rate limits, so they suit a scheduled job better than every PR.",
        "The pedantic and auditor personas produce findings that need triage before you can gate on them."
      ],
      "links": [
        {
          "title": "Documentation",
          "url": "https://docs.zizmor.sh"
        },
        {
          "title": "Audit reference",
          "url": "https://docs.zizmor.sh/audits/"
        }
      ],
      "related": [
        "actionlint",
        "poutine",
        "codeql",
        "pinact"
      ],
      "scenarioIds": [
        "org-ultralytics",
        "org-pwn-requests",
        "app-artipacked"
      ],
      "url": "https://github.com/zizmorcore/zizmor",
      "stats": {
        "stars": 6683,
        "forks": 267,
        "license": "MIT",
        "language": "Rust",
        "archived": false,
        "pushedAt": "2026-10-10",
        "latestRelease": {
          "tag": "v1.30.1",
          "date": "2026-09-09"
        }
      }
    },
    {
      "id": "actionlint",
      "name": "actionlint",
      "repo": "rhysd/actionlint",
      "category": "workflows",
      "model": "oss",
      "rating": 4,
      "ratingNote": "The standard workflow linter for correctness, with a few security checks; pair it with zizmor for the rest.",
      "summary": "Workflow linter that type-checks expressions and runs ShellCheck on run: scripts.",
      "howItWorks": [
        "actionlint is a Go binary that parses workflow files against the full workflow schema. It type-checks every ${{ }} expression, knows which contexts are available in which keys, and validates inputs for popular actions, runner labels, cron syntax and job dependencies.",
        "Shell in run: steps is passed to ShellCheck and Python steps to pyflakes when those are installed. One check flags untrusted inputs such as github.event.pull_request.title used directly in an inline script, which is the classic script injection."
      ],
      "catches": [
        "Syntax and schema errors before a push breaks CI",
        "Expressions that reference missing contexts or have the wrong type",
        "Untrusted event fields inside inline scripts",
        "Shell bugs in run: steps (via ShellCheck)",
        "Invalid runner labels and needs: graphs"
      ],
      "run": "brew install actionlint\nactionlint\n# or without installing:\ndocker run --rm -v \"$PWD:/repo\" -w /repo rhysd/actionlint:latest",
      "network": "Nothing. It reads the workflow files locally.",
      "limits": [
        "Mostly about correctness. It does not check pinning, permissions or dangerous triggers.",
        "No SARIF writer; output is text or a Go template you supply."
      ],
      "links": [
        {
          "title": "List of checks",
          "url": "https://github.com/rhysd/actionlint/blob/main/docs/checks.md"
        }
      ],
      "related": [
        "zizmor",
        "poutine"
      ],
      "url": "https://github.com/rhysd/actionlint",
      "stats": {
        "stars": 4310,
        "forks": 281,
        "license": "MIT",
        "language": "Go",
        "archived": false,
        "pushedAt": "2026-07-16",
        "latestRelease": {
          "tag": "v1.7.12",
          "date": "2026-03-31"
        },
        "scorecard": {
          "score": 3.6,
          "date": "2026-10-05"
        }
      }
    },
    {
      "id": "poutine",
      "name": "poutine",
      "repo": "boostsecurityio/poutine",
      "category": "workflows",
      "model": "oss",
      "rating": 4,
      "ratingNote": "Strong at org-wide scans and build-tool risks, but fewer workflow audits than zizmor and a smaller community.",
      "summary": "Scans CI pipelines in a repo or a whole GitHub or GitLab org for supply-chain misconfigurations, with rules in Rego.",
      "howItWorks": [
        "poutine, from BoostSecurity, reads pipeline definitions (GitHub Actions, GitLab CI and others) into a common model and evaluates rules written in Rego with an embedded Open Policy Agent engine. It can scan a local checkout, one remote repository, or every repository in an organization through the API.",
        "Its distinctive rule is untrusted_checkout_exec: it knows which build tools execute code from the working tree (npm install, make, pip and many more, catalogued in BoostSecurity's Living Off The Pipeline project) and flags them when they run on a checkout of PR code in a privileged workflow. Other rules cover injection, self-hosted runners on PR triggers, default permissions on risky events and known-vulnerable build components."
      ],
      "catches": [
        "Privileged workflows that build or install untrusted PR code",
        "Expression injection in run: steps and scripts",
        "Self-hosted runners reachable from pull requests",
        "Jobs that receive all secrets",
        "Known-vulnerable actions and build components"
      ],
      "run": "brew install poutine\npoutine analyze_local .\n# a whole org, with GH_TOKEN set:\npoutine analyze_org my-org --format sarif",
      "network": "analyze_local sends nothing. analyze_repo and analyze_org call the GitHub or GitLab API with your token and clone the repositories.",
      "limits": [
        "Fewer GitHub-specific audits than zizmor (no impostor commit or cache-poisoning checks).",
        "Writing your own rules means learning Rego."
      ],
      "links": [
        {
          "title": "Living Off The Pipeline",
          "url": "https://boostsecurityio.github.io/lotp/"
        }
      ],
      "related": [
        "zizmor",
        "actionlint",
        "checkov"
      ],
      "scenarioIds": [
        "org-pwn-requests",
        "org-ultralytics"
      ],
      "url": "https://github.com/boostsecurityio/poutine",
      "stats": {
        "stars": 523,
        "forks": 43,
        "license": "Apache-2.0",
        "language": "Go",
        "archived": false,
        "pushedAt": "2026-10-09",
        "latestRelease": {
          "tag": "v1.1.6",
          "date": "2026-05-22"
        },
        "scorecard": {
          "score": 7.6,
          "date": "2026-10-09"
        }
      }
    },
    {
      "id": "pinact",
      "name": "pinact",
      "repo": "suzuki-shunsuke/pinact",
      "category": "pinning",
      "model": "oss",
      "rating": 4,
      "ratingNote": "The simplest way to bulk-pin a repository's actions to SHAs, maintained by a prolific Actions tool author.",
      "summary": "Rewrites uses: references in workflows to full commit SHAs with the version kept as a comment.",
      "howItWorks": [
        "pinact is a Go CLI that finds every uses: line in workflow and action files, resolves the tag or branch to a commit through the GitHub API, and rewrites the line as owner/repo@<sha> # vX.Y.Z. The trailing comment is the format Dependabot and Renovate understand, so they can keep the pins current afterwards.",
        "It can also update pins to the latest release, and a check mode exits non-zero when something is unpinned, so it works as a CI guard."
      ],
      "catches": [
        "Tag and branch references in workflows and composite actions",
        "Pins without a version comment",
        "Out-of-date pins, when run with update"
      ],
      "run": "brew install suzuki-shunsuke/pinact/pinact\npinact run",
      "network": "Calls the GitHub API to resolve tags to SHAs. Set GITHUB_TOKEN to avoid the unauthenticated rate limit.",
      "limits": [
        "Only pins the top-level uses: line. Nested actions inside a composite action stay as their author wrote them.",
        "Does not check that a SHA is reachable from the real repository; zizmor's impostor-commit audit does."
      ],
      "links": [],
      "related": [
        "zizmor"
      ],
      "scenarioIds": [
        "app-tj-actions-changed-files",
        "org-teampcp"
      ],
      "url": "https://github.com/suzuki-shunsuke/pinact",
      "stats": {
        "stars": 1222,
        "forks": 42,
        "license": "MIT",
        "language": "Go",
        "archived": false,
        "pushedAt": "2026-10-10",
        "latestRelease": {
          "tag": "v5.0.0",
          "date": "2026-09-12"
        }
      }
    },
    {
      "id": "harden-runner",
      "name": "Harden-Runner",
      "repo": "step-security/harden-runner",
      "category": "runtime",
      "model": "open-core",
      "rating": 4,
      "ratingNote": "The established runtime monitor for hosted runners and the tool that caught tj-actions, but the insights live in StepSecurity's service.",
      "summary": "Runner agent from StepSecurity that records and can block outbound network calls, file tampering and processes per job.",
      "howItWorks": [
        "You add Harden-Runner as the first step of a job. It installs an agent on the runner that watches DNS lookups, outbound connections, processes and writes to the checked-out source for the rest of the job.",
        "With egress-policy: audit it only records. The recorded endpoints become a baseline you turn into an allowed-endpoints list, and with egress-policy: block anything else is refused. Each run gets an insights page in StepSecurity's app that shows which step called what."
      ],
      "catches": [
        "Exfiltration to unexpected domains or IPs",
        "A compromised action or dependency reaching out at runtime",
        "Source files modified during the build",
        "Unexpected processes started by a step"
      ],
      "run": "# Runs only inside GitHub Actions, as the first step of a job:\n- uses: step-security/harden-runner@<sha> # pin to a release SHA\n  with:\n    egress-policy: audit",
      "network": "Network, process and file events from the job are sent to StepSecurity's API to build the insights page.",
      "limits": [
        "Advanced features and private-repository use beyond the free tier need a StepSecurity plan.",
        "Block mode needs a maintained allow-list per job, which takes effort across many repositories.",
        "It protects the job it runs in, not other jobs on the same self-hosted runner."
      ],
      "links": [
        {
          "title": "StepSecurity docs",
          "url": "https://docs.stepsecurity.io"
        }
      ],
      "related": [
        "zizmor"
      ],
      "scenarioIds": [
        "app-tj-actions-changed-files",
        "org-ghostaction"
      ],
      "url": "https://github.com/step-security/harden-runner",
      "stats": {
        "stars": 1279,
        "forks": 116,
        "license": "Apache-2.0",
        "language": "TypeScript",
        "archived": false,
        "pushedAt": "2026-10-08",
        "latestRelease": {
          "tag": "v2.22.1",
          "date": "2026-10-08"
        },
        "scorecard": {
          "score": 7.8,
          "date": "2026-08-30"
        }
      }
    },
    {
      "id": "gitleaks",
      "name": "Gitleaks",
      "repo": "gitleaks/gitleaks",
      "category": "secrets",
      "model": "oss",
      "rating": 5,
      "ratingNote": "The default open-source secret scanner: one binary, no network, easy rules and baselines.",
      "summary": "Finds secrets in git history, files or stdin with regex, keyword and entropy rules.",
      "howItWorks": [
        "Gitleaks is a Go binary. For a repository it runs git log -p and scans each patch, so it sees secrets that were added and later deleted. It can also scan a plain directory or stdin.",
        "Rules live in a TOML config: each has a regex, optional keywords that must appear first (a cheap pre-filter), an entropy threshold and allowlists. The default config covers a few hundred token formats. Known findings can be ignored with a baseline report, a .gitleaksignore file of fingerprints, or a gitleaks:allow comment.",
        "Output is JSON, CSV, JUnit, SARIF or a custom template, with --redact to keep matches out of logs. The exit code is non-zero when anything is found."
      ],
      "catches": [
        "Cloud keys, GitHub tokens, Slack and Stripe tokens and other known formats",
        "Private keys and generic high-entropy secrets",
        "Secrets removed from HEAD but still in history",
        "New secrets in a PR's commit range"
      ],
      "run": "brew install gitleaks\ngitleaks detect --source . --redact\n# only the commits in a PR:\ngitleaks detect --source . --redact --log-opts=\"origin/main..HEAD\"",
      "network": "Nothing. Scanning is local.",
      "limits": [
        "It does not check whether a secret is live; TruffleHog's verification does.",
        "Custom token formats need your own rules.",
        "The official gitleaks-action needs a free license key for organization accounts, which is why many workflows install the binary instead."
      ],
      "links": [
        {
          "title": "gitleaks-action",
          "url": "https://github.com/gitleaks/gitleaks-action"
        }
      ],
      "related": [
        "checkov"
      ],
      "scenarioIds": [
        "user-mercedes-benz-token-leak",
        "app-artipacked"
      ],
      "url": "https://github.com/gitleaks/gitleaks",
      "stats": {
        "stars": 29825,
        "forks": 2272,
        "license": "MIT",
        "language": "Go",
        "archived": false,
        "pushedAt": "2026-09-30",
        "latestRelease": {
          "tag": "v8.30.1",
          "date": "2026-03-21"
        }
      }
    },
    {
      "id": "osv-scanner",
      "name": "OSV-Scanner",
      "repo": "google/osv-scanner",
      "category": "vulns",
      "model": "oss",
      "rating": 5,
      "ratingNote": "Broad ecosystem coverage, the open OSV.dev data, an offline mode and ignore files with reasons.",
      "summary": "Matches packages from lockfiles, SBOMs and container images against the OSV.dev vulnerability database.",
      "howItWorks": [
        "OSV-Scanner, from Google, extracts package names and versions from lockfiles and manifests (npm, pip, Go, Cargo, Maven, NuGet and many more), SBOMs and container images. It then queries OSV.dev's batch API. OSV.dev aggregates the GitHub Advisory Database, PyPA, RustSec, the Go vulnerability database, OSS-Fuzz, Linux distribution advisories and the OpenSSF malicious-packages feed in one schema.",
        "With --offline-vulnerabilities it uses a local copy of the database instead. For Go (through govulncheck) and Rust it can do call analysis and mark vulnerabilities whose affected functions are never called. An osv-scanner.toml file ignores specific IDs with a reason and an expiry date.",
        "Output is a table, JSON, SARIF, Markdown or HTML. Google publishes reusable workflows for PR and scheduled scans."
      ],
      "catches": [
        "Known vulnerabilities in direct and transitive dependencies",
        "Known malicious package versions (MAL- IDs)",
        "Vulnerable OS packages in container images",
        "Vulnerabilities in vendored C/C++ code identified by commit"
      ],
      "run": "brew install osv-scanner\nosv-scanner scan -L package-lock.json\nosv-scanner scan -r .",
      "network": "Package names and versions (not source code) go to api.osv.dev, unless you use the offline database.",
      "limits": [
        "Lockfile matching reports everything declared, including dev-only packages that never ship. Filter with reachability or ignore entries.",
        "Call analysis covers Go and Rust only.",
        "Like any advisory scanner, it can't see a malicious release before someone reports it."
      ],
      "links": [
        {
          "title": "Documentation",
          "url": "https://google.github.io/osv-scanner/"
        },
        {
          "title": "OSV.dev",
          "url": "https://osv.dev"
        },
        {
          "title": "osv-scanner-action",
          "url": "https://github.com/google/osv-scanner-action"
        }
      ],
      "related": [
        "npm-audit",
        "socket-cli"
      ],
      "url": "https://github.com/google/osv-scanner",
      "stats": {
        "stars": 11159,
        "forks": 811,
        "license": "Apache-2.0",
        "language": "Go",
        "archived": false,
        "pushedAt": "2026-10-09",
        "latestRelease": {
          "tag": "v2.6.0",
          "date": "2026-09-14"
        },
        "scorecard": {
          "score": 8.6,
          "date": "2026-10-09"
        }
      }
    },
    {
      "id": "npm-audit",
      "name": "npm audit",
      "repo": "npm/cli",
      "category": "vulns",
      "model": "oss",
      "license": "Artistic-2.0",
      "rating": 4,
      "ratingNote": "Free and already installed, but npm-only, noisy on dev dependencies and without an ignore file.",
      "summary": "npm's built-in check of your dependency tree against the GitHub Advisory Database.",
      "howItWorks": [
        "npm audit builds the dependency tree from package-lock.json and sends the package names and versions to the registry's bulk advisory endpoint. The registry answers with advisories from the GitHub Advisory Database, and npm works out which installed paths are affected.",
        "--audit-level sets the severity that fails the command and --omit=dev skips dev dependencies. npm audit fix upgrades within semver ranges, and --force allows breaking upgrades. npm audit signatures separately checks registry signatures and provenance attestations for installed packages."
      ],
      "catches": [
        "Known vulnerabilities in npm packages, direct and transitive",
        "The dependency path that pulls each one in",
        "Packages with invalid registry signatures or provenance"
      ],
      "run": "npm audit --audit-level=high --omit=dev\nnpm audit --json > npm-audit.json\nnpm audit signatures",
      "network": "The dependency tree (package names and versions) goes to the npm registry.",
      "limits": [
        "No built-in way to ignore an advisory you have assessed.",
        "Reports dev dependencies unless told not to, which is most of the noise.",
        "npm audit fix --force can make major-version changes you didn't review."
      ],
      "links": [
        {
          "title": "npm audit docs",
          "url": "https://docs.npmjs.com/cli/commands/npm-audit"
        }
      ],
      "related": [
        "osv-scanner",
        "socket-cli"
      ],
      "url": "https://github.com/npm/cli",
      "stats": {
        "stars": 10182,
        "forks": 4847,
        "license": null,
        "language": "JavaScript",
        "archived": false,
        "pushedAt": "2026-10-09",
        "latestRelease": {
          "tag": "v12.2.0",
          "date": "2026-09-30"
        },
        "scorecard": {
          "score": 6.8,
          "date": "2026-10-05"
        }
      }
    },
    {
      "id": "socket-cli",
      "name": "Socket CLI",
      "repo": "SocketDev/socket-cli",
      "category": "malicious",
      "model": "oss-client",
      "rating": 4,
      "ratingNote": "Catches malicious packages before they have a CVE, but the analysis runs in Socket's service and needs an API key.",
      "summary": "Client for Socket, which analyzes what each package version does to spot malware and risky behaviour.",
      "howItWorks": [
        "Socket analyzes every version published to npm, PyPI and other registries: install scripts, network and shell access, filesystem and environment variable access, obfuscated code, typosquatted names and maintainer changes, plus AI-assisted malware review. It does this when a version is published, so verdicts are ready before you install.",
        "The CLI uploads your manifests and lockfiles (socket scan create) and reports alerts against your organization's policy. socket npm wraps npm install and checks packages before they install. The GitHub app comments on pull requests that add risky dependencies."
      ],
      "catches": [
        "Known malware and newly published malicious versions",
        "Install scripts, network calls and obfuscation in new dependencies",
        "Typosquats of popular packages",
        "Unexpected new maintainers or protestware"
      ],
      "run": "npm install -g socket\nsocket login\nsocket scan create --repo my-repo .",
      "network": "Manifest and lockfile contents (package names and versions) go to Socket's API. Source code is not uploaded.",
      "limits": [
        "Needs a Socket account and API token; fork PRs don't get the secret, so make the step skip cleanly.",
        "Verdicts come from Socket's service, so you can't reproduce them offline."
      ],
      "links": [
        {
          "title": "Socket docs",
          "url": "https://docs.socket.dev"
        }
      ],
      "related": [
        "osv-scanner",
        "npm-audit"
      ],
      "scenarioIds": [
        "org-shai-hulud",
        "org-nx-s1ngularity"
      ],
      "url": "https://github.com/SocketDev/socket-cli",
      "stats": {
        "stars": 323,
        "forks": 68,
        "license": "MIT",
        "language": "TypeScript",
        "archived": false,
        "pushedAt": "2026-10-10",
        "latestRelease": {
          "tag": "v1.1.146"
        }
      }
    },
    {
      "id": "semgrep",
      "name": "Semgrep CE",
      "repo": "semgrep/semgrep",
      "category": "sast",
      "model": "open-core",
      "rating": 4,
      "ratingNote": "Fast, readable rules and a large registry, but cross-file dataflow and many rules are only in the paid product.",
      "summary": "Pattern-based code scanner whose rules look like the code they match.",
      "howItWorks": [
        "Semgrep parses source into a generic syntax tree for each of its supported languages and matches rules written in YAML. A rule pattern is code with metavariables ($X) and ellipses (...), so a rule for eval($USER_INPUT) looks like the code it finds. Taint mode tracks data from sources to sinks within a file.",
        "Rules come from your own files or from the Semgrep Registry (for example --config p/ci). Since December 2024 Semgrep's own rules are under the Semgrep Rules License, which allows internal use but not use in competing products. That change led to the Opengrep fork.",
        "Output is text, JSON, SARIF or JUnit, and --error makes the exit code non-zero on findings. The commercial engine adds cross-file and cross-function dataflow."
      ],
      "catches": [
        "Injection sinks fed by request data (SQL, command, template)",
        "Dangerous functions and insecure defaults per framework",
        "Hardcoded credentials and weak crypto",
        "Your own banned patterns, written in minutes"
      ],
      "run": "pipx install semgrep\nsemgrep scan --config p/ci --metrics off --error .",
      "network": "Registry rules are downloaded at start. Usage metrics are sent when you use registry configs unless you pass --metrics off.",
      "limits": [
        "Community Edition dataflow stops at the file boundary.",
        "Registry rule licensing changed in 2024; check it fits how you use them."
      ],
      "links": [
        {
          "title": "Documentation",
          "url": "https://semgrep.dev/docs/"
        },
        {
          "title": "Writing rules",
          "url": "https://semgrep.dev/docs/writing-rules/overview"
        }
      ],
      "related": [
        "codeql"
      ],
      "url": "https://github.com/semgrep/semgrep",
      "stats": {
        "stars": 16947,
        "forks": 1097,
        "license": "LGPL-2.1",
        "language": "C",
        "archived": false,
        "pushedAt": "2026-10-09",
        "latestRelease": {
          "tag": "v1.180.0",
          "date": "2026-10-07"
        }
      }
    },
    {
      "id": "codeql",
      "name": "CodeQL",
      "repo": "github/codeql",
      "category": "sast",
      "alsoIn": [
        "workflows"
      ],
      "model": "source-available",
      "rating": 4,
      "ratingNote": "The deepest analysis here and built into GitHub, but slow and only free for public repositories.",
      "summary": "GitHub's semantic code analysis: code becomes a database, queries do interprocedural taint tracking.",
      "howItWorks": [
        "CodeQL first extracts a relational database from the code. For compiled languages it watches the build, for others it reads the source. Queries written in QL then run against that database, with libraries for interprocedural dataflow and taint tracking from sources (request data, event fields) to sinks (queries, shells, file paths).",
        "On GitHub you turn it on with default setup in the repository settings or with github/codeql-action in a workflow, and results appear as code scanning alerts on PRs. Since April 2025 it also analyzes GitHub Actions workflows for injection, missing permissions and untrusted checkouts.",
        "The queries in github/codeql are MIT licensed. The CLI and engine are under the GitHub CodeQL Terms: free for open source and research, and for private repositories it needs GitHub Code Security."
      ],
      "catches": [
        "Injection and path traversal across function and file boundaries",
        "Unsafe deserialization and SSRF",
        "Script injection and untrusted checkout in Actions workflows",
        "Custom variant analysis written as your own queries"
      ],
      "run": "gh extension install github/gh-codeql\ngh codeql database create db --language=javascript\ngh codeql database analyze db --format=sarif-latest --output=codeql.sarif",
      "network": "Local analysis sends nothing. On GitHub, results are uploaded as code scanning alerts.",
      "limits": [
        "Analysis takes minutes to an hour on large codebases.",
        "Private repositories need a paid GitHub Code Security license.",
        "Writing QL queries is a skill of its own."
      ],
      "links": [
        {
          "title": "CodeQL docs",
          "url": "https://codeql.github.com/docs/"
        },
        {
          "title": "Actions workflow analysis GA",
          "url": "https://github.blog/changelog/2025-04-22-github-actions-workflow-security-analysis-with-codeql-is-now-generally-available/"
        }
      ],
      "related": [
        "semgrep",
        "zizmor"
      ],
      "scenarioIds": [
        "org-pwn-requests"
      ],
      "url": "https://github.com/github/codeql",
      "stats": {
        "stars": 10182,
        "forks": 2117,
        "license": "MIT",
        "language": "CodeQL",
        "archived": false,
        "pushedAt": "2026-10-09",
        "scorecard": {
          "score": 5.8,
          "date": "2026-10-05"
        }
      }
    },
    {
      "id": "checkov",
      "name": "Checkov",
      "repo": "bridgecrewio/checkov",
      "category": "iac",
      "alsoIn": [
        "workflows",
        "posture",
        "secrets"
      ],
      "model": "open-core",
      "rating": 5,
      "ratingNote": "The widest free IaC rule set, released several times a week and easy to drop into CI, though severities and SCA need a Prisma Cloud key.",
      "summary": "Scans Terraform, CloudFormation, Kubernetes, Helm, Dockerfiles, CI workflows and GitHub org settings for misconfigurations using Python and YAML policies.",
      "howItWorks": [
        "Checkov is a Python CLI maintained by Palo Alto Networks (Prisma Cloud, formerly Bridgecrew). Each framework has its own parser (HCL2 for Terraform, YAML and JSON for CloudFormation and Kubernetes, a Dockerfile parser, Bicep and ARM parsers, and Terraform plan JSON). Attribute checks are Python classes that get one resource's parsed config and return passed or failed. They have ids like CKV_AWS_20.",
        "For Terraform, CloudFormation, Kubernetes and several other frameworks it also builds an in-memory graph of resources and the references between them (for Terraform, after rendering variables, locals and modules). Graph checks (CKV2_*) are YAML policies made of attribute, connection and filter conditions joined with and/or/not, so a rule can ask whether a bucket has a connected public access block rather than only looking at the bucket. Your own Python or YAML checks load from --external-checks-dir.",
        "The github_actions framework parses workflow YAML and runs seven job checks plus one graph check: ACTIONS_ALLOW_UNSECURE_COMMANDS, a regex list of untrusted github.event fields inside run: (CKV_GHA_2), curl with secrets, netcat to an IP, missing cosign signing or SBOM attestation, non-empty workflow_dispatch inputs, and write-all top-level permissions. The github_configuration framework calls the GitHub REST and GraphQL APIs with GITHUB_TOKEN (org settings, branch protection on the current branch, webhooks, collaborators, org admins), saves the JSON under github_conf/ and runs CKV_GITHUB_* checks on it. The secrets framework uses bc-detect-secrets, Bridgecrew's fork of Yelp's detect-secrets, with regex, keyword and entropy detectors.",
        "Output is cli, json, sarif, junitxml, csv, cyclonedx, spdx, gitlab_sast or github_failed_only, and the exit code is non-zero on any failed check unless --soft-fail is set. Suppress with a checkov:skip=CKV_AWS_20:reason comment inside the resource, a checkov.io/skip annotation in Kubernetes, --skip-check with wildcards, or a .checkov.baseline file. Severities, SCA (sca_package, sca_image) and enforcement rules come from Prisma Cloud and only work with --bc-api-key."
      ],
      "catches": [
        "Public buckets, open security groups and missing encryption in Terraform, CloudFormation, ARM, Bicep and Serverless",
        "Privileged pods, hostPath mounts and missing limits in Kubernetes, Helm and Kustomize",
        "Dockerfiles with no non-root USER or no HEALTHCHECK",
        "Untrusted github.event fields expanded inside workflow run: steps",
        "ACTIONS_ALLOW_UNSECURE_COMMANDS and write-all workflow permissions",
        "Org 2FA, SSO and branch protection gaps read from the GitHub API",
        "Hardcoded credentials in IaC and, with a flag, in any file"
      ],
      "run": "pip3 install checkov\ncheckov -d . --skip-download\ncheckov -d . --framework github_actions --compact",
      "ci": "checkov:\n  runs-on: ubuntu-latest\n  permissions:\n    contents: read\n    security-events: write\n  steps:\n    - uses: actions/checkout@<sha> # v7.0.1\n      with:\n        persist-credentials: false\n    - uses: bridgecrewio/checkov-action@<sha> # v12.3131.0\n      with:\n        directory: .\n        output_format: cli,sarif\n        output_file_path: console,results.sarif\n    - uses: github/codeql-action/upload-sarif@<sha> # v4.38.3\n      if: success() || failure()\n      with:\n        sarif_file: results.sarif",
      "network": "By default it calls Prisma Cloud's API to add guideline links to results (the README says no identifiable customer data is sent); --skip-download turns that off. With --bc-api-key, results and SCA package data go to Prisma Cloud, and the github_configuration framework reads settings from the GitHub API with your token.",
      "limits": [
        "Without a Prisma Cloud API key findings have no severity, so you cannot gate CI on HIGH and above; you gate on individual checks instead.",
        "Workflow coverage is thin: eight checks, the injection check is a regex over run: text, and nothing flags unpinned actions, pull_request_target or cache use. Run zizmor for workflows.",
        "The default rule set is large and noisy on real Terraform. Expect to spend time on --skip-check lists, inline skips or a baseline.",
        "The official action runs ghcr.io/bridgecrewio/checkov by version tag, not by digest, so pinning the action SHA does not pin the image."
      ],
      "links": [
        {
          "title": "CLI command reference",
          "url": "https://www.checkov.io/2.Basics/CLI%20Command%20Reference.html"
        },
        {
          "title": "GitHub Actions policy index",
          "url": "https://www.checkov.io/5.Policy%20Index/github_actions.html"
        },
        {
          "title": "YAML custom policies",
          "url": "https://www.checkov.io/3.Custom%20Policies/YAML%20Custom%20Policies.html"
        },
        {
          "title": "checkov-action",
          "url": "https://github.com/bridgecrewio/checkov-action"
        }
      ],
      "related": [
        "kics",
        "zizmor",
        "hadolint"
      ],
      "url": "https://github.com/bridgecrewio/checkov",
      "stats": {
        "stars": 9061,
        "forks": 1431,
        "license": "Apache-2.0",
        "language": "Python",
        "archived": false,
        "pushedAt": "2026-10-07",
        "latestRelease": {
          "tag": "3.3.26",
          "date": "2026-10-07"
        },
        "scorecard": {
          "score": 7,
          "date": "2022-11-28"
        }
      }
    },
    {
      "id": "kics",
      "name": "KICS",
      "repo": "Checkmarx/kics",
      "category": "iac",
      "alsoIn": [
        "workflows"
      ],
      "model": "oss",
      "rating": 3,
      "ratingNote": "A broad, fully open Rego query set, but its own action and Docker images were hijacked twice in 2026 and new versions now ship as source only.",
      "summary": "Runs Rego queries against Terraform, CloudFormation, Kubernetes, Dockerfiles, Ansible, GitHub workflows and other IaC to find misconfigurations.",
      "howItWorks": [
        "KICS (Keeping Infrastructure as Code Secure) is a Go binary from Checkmarx. It walks local paths and archives, or copies git, S3 and GCS sources to a temp folder first, works out the platform of each file (Terraform, CloudFormation, Kubernetes, Helm, Dockerfile, Docker Compose, Ansible, OpenAPI, Pulumi, Crossplane, Bicep, GitHub workflows and more) and parses it into normalized JSON.",
        "Queries are written in Rego and run by an embedded Open Policy Agent engine against that JSON, with each platform's queries running concurrently. Every query is a folder with query.rego, metadata.json (id, severity, category, description) and test fixtures, so writing your own means adding a folder and pointing --queries-path at it. The GitHub workflow queries flag untrusted event fields in run: and github-script blocks per trigger, unsecured commands, and uses: refs that are not a 40-character SHA (anything under actions/ is exempt).",
        "Secret detection is the one query written in Go. It applies regex rules from regex_rules.json, with Shannon entropy bounds on capture groups and allow rules to drop false positives, and you can swap in your own rules with --secrets-regexes-path.",
        "Results are written as JSON by default, or SARIF, HTML, PDF, JUnit, SonarQube, GitLab SAST, CycloneDX, ASFF, CSV and Code Climate. The exit code encodes the highest severity found (60 critical down to 20 info), adjustable with --fail-on and --ignore-on-exit. Inline # kics-scan ignore, ignore-line, ignore-block and disable=<query id> comments suppress findings, and kics remediate applies automatic fixes for some queries from a results file."
      ],
      "catches": [
        "Public storage, open security groups and missing encryption in Terraform, CloudFormation, ARM, Bicep and Pulumi",
        "Privileged containers and host namespace use in Kubernetes, Helm, Knative and Crossplane",
        "Dockerfile and Docker Compose misconfigurations",
        "Untrusted event fields in workflow run: and github-script blocks",
        "Third-party actions not pinned to a full commit SHA",
        "ACTIONS_ALLOW_UNSECURE_COMMANDS in workflows",
        "Hardcoded passwords and keys in scanned IaC files"
      ],
      "run": "brew install kics\nexport KICS_QUERIES_PATH=\"$(brew --prefix kics)/share/kics/assets/queries\"\nkics scan -p . -o kics-results --report-formats json,sarif",
      "ci": "kics:\n  runs-on: ubuntu-latest\n  permissions:\n    contents: read\n    security-events: write\n  steps:\n    - uses: actions/checkout@<sha> # v7.0.1\n      with:\n        persist-credentials: false\n    - run: mkdir -p kics-results\n    - uses: Checkmarx/kics-github-action@<sha> # v2.1.20\n      with:\n        path: .\n        output_path: kics-results\n        output_formats: json,sarif\n        ignore_on_exit: results\n    - uses: github/codeql-action/upload-sarif@<sha> # v4.38.3\n      with:\n        sarif_file: kics-results/results.sarif",
      "network": "A local scan sends nothing except crash reports to sentry.io, which you turn off by setting DISABLE_CRASH_REPORT to 0 or false. Git, S3 and GCS paths are downloaded before scanning.",
      "limits": [
        "On 23 March 2026 (TeamPCP) attackers used stolen credentials to repoint all 35 tags of Checkmarx/kics-github-action to a credential stealer. On 22 April 2026 the checkmarx/kics Docker Hub tags (latest, alpine, debian, v2.1.20) were overwritten with a build that sent scan results to an attacker domain. Pin the action by SHA, pin images by digest, and rotate secrets if you ran it in either window.",
        "The action's Dockerfile builds FROM checkmarx/kics:v2.1.20 by tag and on wolfi-base:latest, so pinning the action SHA does not pin the scanner image.",
        "Since the April incident v2.1.21 and v2.2.0 shipped as source code only. Docker Hub and the prebuilt binaries stop at v2.1.20, so a current version means Homebrew or building from source.",
        "Only four GitHub workflow queries, all regex over the YAML with no dataflow through env: or step outputs. Use zizmor for workflow analysis."
      ],
      "links": [
        {
          "title": "Architecture",
          "url": "https://docs.kics.io/latest/architecture/"
        },
        {
          "title": "Command reference",
          "url": "https://docs.kics.io/latest/commands/"
        },
        {
          "title": "kics-github-action",
          "url": "https://github.com/Checkmarx/kics-github-action"
        },
        {
          "title": "Docker on the April 2026 KICS image compromise",
          "url": "https://www.docker.com/blog/trivy-kics-and-the-shape-of-supply-chain-attacks-so-far-in-2026/"
        }
      ],
      "related": [
        "checkov",
        "conftest",
        "terrascan",
        "zizmor"
      ],
      "scenarioIds": [
        "org-teampcp"
      ],
      "url": "https://github.com/Checkmarx/kics",
      "stats": {
        "stars": 2716,
        "forks": 386,
        "license": "Apache-2.0",
        "language": "Open Policy Agent",
        "archived": false,
        "pushedAt": "2026-10-08",
        "latestRelease": {
          "tag": "v2.2.0",
          "date": "2026-09-17"
        }
      }
    },
    {
      "id": "tfsec",
      "name": "tfsec",
      "repo": "aquasecurity/tfsec",
      "category": "iac",
      "model": "oss",
      "rating": 1,
      "ratingNote": "Aqua has moved the engine into Trivy and asks users to switch; tfsec only gets dependency bumps and last shipped in May 2025.",
      "summary": "Terraform-only static scanner that evaluates HCL with modules and variables. Its engine now lives in Trivy as trivy config.",
      "howItWorks": [
        "tfsec is a Go CLI for Terraform only. It parses .tf files with HashiCorp's HCL library and evaluates them the way Terraform would: variables and tfvars files, locals, functions such as concat(), and local and remote modules. Remote modules are downloaded unless --no-module-downloads is set.",
        "Built-in checks come from Aqua's defsec library and are written in Go, covering AWS, Azure, Google Cloud and others, plus four GitHub provider checks (plaintext action secrets, signed commits in branch protection, vulnerability alerts, private repositories). You can add JSON or YAML checks in files ending _tfchecks.json or _tfchecks.yaml under .tfsec/, built from requiredTypes, requiredLabels and matchSpec actions such as contains, equals and regexMatches, or write Rego policies.",
        "Output is lovely (the default terminal view), json, sarif, csv, checkstyle, junit or text. The run fails on findings unless --soft-fail is set, and --minimum-severity filters. A #tfsec:ignore:<rule> comment on the line or block suppresses a finding, and adding :exp:YYYY-MM-DD makes the ignore expire."
      ],
      "catches": [
        "Public S3 buckets and missing bucket encryption",
        "Security groups open to 0.0.0.0/0",
        "Unencrypted databases, disks and queues across clouds",
        "Plaintext values in github_actions_secret resources",
        "GitHub repositories created public or without vulnerability alerts",
        "Misconfigurations inside remote modules after they are evaluated"
      ],
      "run": "brew install tfsec\ntfsec .\n# replacement with the same engine:\ntrivy config .",
      "network": "Remote Terraform modules are downloaded during the scan unless you pass --no-module-downloads. --custom-check-url and --config-file-url fetch files from the URL you give.",
      "limits": [
        "Deprecated in favour of Trivy. Aqua says engineering attention goes to Trivy, and the last release, v1.28.14 in May 2025, only fixed CVEs in dependencies.",
        "New cloud resources and provider changes are not getting checks. Move to trivy config, which has the same engine plus more languages.",
        "Terraform only. It does not read Kubernetes, Dockerfiles or workflow files.",
        "The migration guide maps commands and flags but not ignore comments or custom JSON/YAML checks, so plan to rewrite those."
      ],
      "links": [
        {
          "title": "Documentation",
          "url": "https://aquasecurity.github.io/tfsec/latest/"
        },
        {
          "title": "tfsec to Trivy migration guide",
          "url": "https://github.com/aquasecurity/tfsec/blob/master/tfsec-to-trivy-migration-guide.md"
        },
        {
          "title": "Custom checks",
          "url": "https://aquasecurity.github.io/tfsec/latest/guides/configuration/custom-checks/"
        }
      ],
      "related": [
        "checkov",
        "kics"
      ],
      "url": "https://github.com/aquasecurity/tfsec",
      "stats": {
        "stars": 7048,
        "forks": 559,
        "license": "MIT",
        "language": "Go",
        "archived": false,
        "pushedAt": "2026-03-25",
        "latestRelease": {
          "tag": "v1.28.14",
          "date": "2025-05-02"
        },
        "scorecard": {
          "score": 4.7,
          "date": "2026-03-16"
        }
      }
    },
    {
      "id": "terrascan",
      "name": "Terrascan",
      "repo": "tenable/terrascan",
      "category": "iac",
      "model": "oss",
      "rating": 1,
      "ratingNote": "Tenable archived the repository on 20 November 2025 and the last release dates from September 2024.",
      "summary": "Archived Rego-based scanner for Terraform, CloudFormation, ARM, Kubernetes, Helm, Kustomize and Dockerfiles, formerly maintained by Tenable.",
      "howItWorks": [
        "Terrascan is a Go CLI. On first run (or with terrascan init) it clones its policies from the master branch of github.com/tenable/terrascan into ~/.terrascan, under pkg/policies/opa/rego.",
        "IaC providers parse Terraform HCL2, CloudFormation, ARM, Kubernetes YAML or JSON, Helm v3, Kustomize and Dockerfiles into a normalized JSON config per resource type, which you can print with --config-only. Policies are Rego files paired with a JSON rule file (name, severity, category, reference_id) and run in an embedded OPA engine against that config.",
        "Results go out through human, JSON, YAML, XML, JUnit XML and SARIF writers. --find-vuln looks up images referenced in the IaC in the registry's own vulnerability scanning (AWS, Azure, GCP, Harbor), --webhook-url posts results to a URL, and terrascan server runs the same scanner as an HTTP API."
      ],
      "catches": [
        "Public storage, open security groups and missing encryption in Terraform, CloudFormation and ARM",
        "Privileged pods and missing security contexts in Kubernetes, Helm and Kustomize",
        "Dockerfile misconfigurations",
        "GitHub repository and webhook resources defined with the Terraform GitHub provider",
        "Known CVEs in referenced images, through the registry's scanner"
      ],
      "run": "brew install terrascan\nterrascan scan -i terraform -d .",
      "network": "terrascan init clones the policy repository from GitHub. --find-vuln calls the registry provider's API, --webhook-url posts results, and -r git/s3/gcs/http downloads the remote IaC.",
      "limits": [
        "Archived on 20 November 2025. No new policies, parser fixes or dependency updates, and Homebrew has marked its formula deprecated.",
        "Policies are pulled at run time from the archived repository's master branch, so the rule set is frozen.",
        "Migrate to Checkov, KICS or trivy config."
      ],
      "links": [
        {
          "title": "Policy format",
          "url": "https://github.com/tenable/terrascan/blob/master/docs/policies.md"
        },
        {
          "title": "terrascan-action",
          "url": "https://github.com/tenable/terrascan-action"
        }
      ],
      "related": [
        "checkov",
        "kics"
      ],
      "url": "https://github.com/tenable/terrascan",
      "stats": {
        "stars": 5213,
        "forks": 554,
        "license": "Apache-2.0",
        "language": "Go",
        "archived": true,
        "pushedAt": "2025-11-20",
        "latestRelease": {
          "tag": "v1.19.9",
          "date": "2024-09-18"
        }
      }
    },
    {
      "id": "hadolint",
      "name": "Hadolint",
      "repo": "hadolint/hadolint",
      "category": "iac",
      "model": "oss",
      "rating": 4,
      "ratingNote": "The standard Dockerfile linter and actively released again, but most rules are about reproducibility and hygiene, so pair it with an image scanner.",
      "summary": "Lints Dockerfiles against best-practice rules and runs ShellCheck on the shell script in every RUN instruction.",
      "howItWorks": [
        "Hadolint is written in Haskell. It parses the Dockerfile into an AST with the language-docker library and runs its DL rules over the instruction list. Because rules see the whole file, some track state, such as which USER is set last.",
        "The shell code in each RUN instruction is handed to ShellCheck, which hadolint embeds, and those findings come back as SC rules next to the DL ones. Hadolint never builds the image, pulls the base image or looks at what is installed in it.",
        "Settings come from .hadolint.yaml (ignored rules, severity overrides, failure-threshold, trustedRegistries for DL3026, a label schema) or from CLI flags. A # hadolint ignore=DL3008,SC2086 comment covers the next instruction and # hadolint global ignore=... covers the file. Output is tty, json, checkstyle, codeclimate, gitlab_codeclimate, gnu, codacy, sonarqube, sarif or junit, and the exit code is non-zero when a finding reaches the failure threshold."
      ],
      "catches": [
        "FROM images with no tag or with :latest (DL3006, DL3007)",
        "Unpinned package versions in apt-get, apk, pip, npm, gem and go install",
        "Last USER is root, or sudo used in RUN (DL3002, DL3004)",
        "ADD used where COPY would do (DL3020)",
        "Base images from registries outside your trusted list (DL3026)",
        "Credential-looking names in ARG or ENV (DL3064)",
        "Shell bugs in RUN lines and pipes without pipefail (ShellCheck, DL4006)"
      ],
      "run": "brew install hadolint\nhadolint Dockerfile\n# or without installing:\ndocker run --rm -i hadolint/hadolint < Dockerfile",
      "ci": "hadolint:\n  runs-on: ubuntu-latest\n  permissions:\n    contents: read\n    security-events: write\n  steps:\n    - uses: actions/checkout@<sha> # v7.0.1\n      with:\n        persist-credentials: false\n    - uses: hadolint/hadolint-action@<sha> # v3.5.0\n      with:\n        dockerfile: Dockerfile\n        format: sarif\n        output-file: hadolint.sarif\n        no-fail: true\n    - uses: github/codeql-action/upload-sarif@<sha> # v4.38.3\n      with:\n        sarif_file: hadolint.sarif",
      "network": "Nothing. It reads the Dockerfile locally and does not contact registries.",
      "limits": [
        "Only sees the Dockerfile text. It cannot tell you about CVEs or secrets baked into the base image or the built layers.",
        "DL3006 and DL3007 accept any explicit tag, and no rule requires pinning FROM to a sha256 digest.",
        "Release gaps have been long (v2.12.0 in 2022, then v2.13 in 2025), so check the rule list against the version you actually run."
      ],
      "links": [
        {
          "title": "hadolint-action",
          "url": "https://github.com/hadolint/hadolint-action"
        },
        {
          "title": "Integration guide",
          "url": "https://github.com/hadolint/hadolint/blob/master/docs/INTEGRATION.md"
        }
      ],
      "related": [
        "checkov",
        "kics"
      ],
      "url": "https://github.com/hadolint/hadolint",
      "stats": {
        "stars": 12466,
        "forks": 507,
        "license": "GPL-3.0",
        "language": "Haskell",
        "archived": false,
        "pushedAt": "2026-09-25",
        "latestRelease": {
          "tag": "v2.15.1",
          "date": "2026-07-31"
        },
        "scorecard": {
          "score": 4.3,
          "date": "2026-10-05"
        }
      }
    },
    {
      "id": "conftest",
      "name": "Conftest",
      "repo": "open-policy-agent/conftest",
      "category": "iac",
      "model": "oss",
      "rating": 4,
      "ratingNote": "Very flexible and actively released, but it ships no rules, so every check is Rego you write and maintain yourself.",
      "summary": "Tests any structured config file, including workflow YAML, Terraform and Kubernetes manifests, against Rego policies you write.",
      "howItWorks": [
        "Conftest is a Go CLI around the Open Policy Agent Rego engine, maintained under the open-policy-agent GitHub org. It picks a parser by file extension (YAML, JSON, HCL2, Dockerfile, TOML, INI, XML, CUE, Jsonnet, .env, HOCON, CycloneDX, SPDX, CODEOWNERS and others) or by --parser, and turns each file into the Rego input document. HCL is converted as written, so variables and modules are not evaluated.",
        "Policies load from policy/ (or --policy). In the main namespace by default, rules named deny, violation (which can return structured data) and warn, optionally with a suffix such as deny_unpinned, produce failures or warnings. An exception rule can exempt matching inputs from named rules. --data adds JSON or YAML data files, and --combine passes all files as one array so a rule can compare files.",
        "Output is stdout, json, tap, table, junit, github (workflow annotations), azuredevops or sarif. Failures give a non-zero exit code, and --fail-on-warn makes warnings fail too. conftest verify runs Rego unit tests for your policies, and conftest push and conftest pull share policy bundles through OCI registries, git or HTTPS.",
        "For GitHub this means you write the rules: deny pull_request_target triggers, require uses: to end in a 40-character SHA, require a permissions: block, or check CODEOWNERS (parser added in v0.71.0) and github provider Terraform."
      ],
      "catches": [
        "Any rule you can write in Rego over YAML, JSON, HCL2, TOML, INI, XML or Dockerfiles",
        "Workflow policies such as no pull_request_target and SHA-pinned uses:",
        "Kubernetes manifests and rendered Helm output (runAsNonRoot, required labels)",
        "Terraform plan JSON checks with resolved values",
        "Cross-file checks with --combine",
        "CODEOWNERS coverage rules"
      ],
      "run": "brew install conftest\nconftest test --policy policy .github/workflows/\nconftest verify --policy policy",
      "ci": "- uses: actions/checkout@<sha> # v7.0.1\n  with:\n    persist-credentials: false\n- name: Test workflows against policy/\n  run: >\n    docker run --rm -v \"$PWD:/project\"\n    openpolicyagent/conftest:v0.71.1\n    test --policy policy --output github .github/workflows",
      "network": "Nothing during conftest test. conftest pull, test --update and plugin installs download from the OCI registry, git or HTTPS location you give.",
      "limits": [
        "No built-in policies. Rego has a learning curve, and untested policies quietly pass everything, so write conftest verify tests.",
        "It checks files as parsed. Terraform variables, modules and expressions are not resolved unless you test terraform show -json plan output.",
        "Policies fetched with --update or conftest pull change whenever the source changes. Pin an OCI digest or git ref.",
        "There is no official GitHub Action; run the binary or the Docker image yourself."
      ],
      "links": [
        {
          "title": "Documentation",
          "url": "https://www.conftest.dev/"
        },
        {
          "title": "Options and output formats",
          "url": "https://www.conftest.dev/options/"
        },
        {
          "title": "Sharing policies",
          "url": "https://www.conftest.dev/sharing/"
        }
      ],
      "related": [
        "checkov",
        "kics",
        "zizmor",
        "actionlint"
      ],
      "url": "https://github.com/open-policy-agent/conftest",
      "stats": {
        "stars": 3280,
        "forks": 365,
        "license": null,
        "language": "Go",
        "archived": false,
        "pushedAt": "2026-10-09",
        "latestRelease": {
          "tag": "v0.71.1",
          "date": "2026-10-06"
        },
        "scorecard": {
          "score": 7,
          "date": "2026-10-05"
        }
      }
    },
    {
      "id": "scorecard",
      "name": "OpenSSF Scorecard",
      "repo": "ossf/scorecard",
      "category": "posture",
      "model": "oss",
      "rating": 4,
      "ratingNote": "The standard way to judge a dependency's security hygiene; some checks are heuristics, so read the details, not just the score.",
      "summary": "Scores a repository's security practices 0 to 10 from about 18 automated checks.",
      "howItWorks": [
        "Scorecard reads a repository through the GitHub API and a clone and runs about 18 checks: branch protection, code review, dangerous workflow patterns, token permissions, pinned dependencies, signed releases, SAST, fuzzing, maintenance activity, known vulnerabilities (via OSV) and more. Each check scores 0 to 10 and the overall score is a risk-weighted average.",
        "OpenSSF scans over a million popular repositories weekly and publishes the results through api.securityscorecards.dev and the scorecard.dev viewer, which is where this page's Scorecard column comes from. ossf/scorecard-action runs it on your own repository and uploads SARIF to code scanning."
      ],
      "catches": [
        "Workflows with dangerous triggers or write-all tokens",
        "Unpinned actions and dependencies",
        "Missing branch protection or code review",
        "Unmaintained projects you depend on"
      ],
      "run": "brew install scorecard\nGITHUB_AUTH_TOKEN=... scorecard --repo=github.com/ossf/scorecard",
      "network": "Calls the GitHub API with your token and clones the repository. scorecard-action can publish your results to the public dataset.",
      "limits": [
        "Some checks are heuristics, for example detecting SAST tools or fuzzing by name.",
        "A high score says the project protects itself well, not that its code is free of bugs."
      ],
      "links": [
        {
          "title": "scorecard.dev",
          "url": "https://scorecard.dev"
        },
        {
          "title": "Check documentation",
          "url": "https://github.com/ossf/scorecard/blob/main/docs/checks.md"
        },
        {
          "title": "scorecard-action",
          "url": "https://github.com/ossf/scorecard-action"
        }
      ],
      "related": [
        "zizmor",
        "osv-scanner"
      ],
      "url": "https://github.com/ossf/scorecard",
      "stats": {
        "stars": 5747,
        "forks": 741,
        "license": "Apache-2.0",
        "language": "Go",
        "archived": false,
        "pushedAt": "2026-10-09",
        "latestRelease": {
          "tag": "v5.5.0",
          "date": "2026-04-23"
        },
        "scorecard": {
          "score": 8.3,
          "date": "2026-10-10"
        }
      }
    }
  ],
  "pipeline": [
    {
      "stage": "Release-age cooldown",
      "toolIds": [],
      "blocksOn": "A new or changed dependency version published fewer than N days ago",
      "note": "Malicious releases are usually reported and pulled quickly, so waiting a few days before adopting a new version skips most of them. Renovate (minimumReleaseAge), Dependabot (cooldown) and pnpm (minimumReleaseAge) can do this for you."
    },
    {
      "stage": "Version pinning",
      "toolIds": [],
      "blocksOn": "Wildcard ranges or git dependencies without a commit (advisory at first)",
      "note": "Checks the declared ranges in package.json and the lockfile, without installing anything."
    },
    {
      "stage": "Known vulnerabilities",
      "toolIds": [
        "npm-audit",
        "osv-scanner"
      ],
      "blocksOn": "Advisories at or above your chosen severity",
      "note": "npm audit asks the registry. OSV-Scanner reads the lockfile and asks OSV.dev. They use overlapping but different data, so running both catches more."
    },
    {
      "stage": "Reachability",
      "toolIds": [
        "osv-scanner"
      ],
      "blocksOn": "Nothing on its own. It only suppresses findings",
      "note": "Drops findings for packages that are not in the artifact you deploy, such as dev-only tooling, and records each decision as an OpenVEX statement."
    },
    {
      "stage": "Workflow analysis",
      "toolIds": [
        "zizmor",
        "actionlint"
      ],
      "blocksOn": "Findings in .github/workflows and action.yml",
      "note": "Template injection, pull_request_target misuse, unpinned actions, credential persistence. Run offline in PRs and keep online audits for a scheduled job."
    },
    {
      "stage": "Code scanning",
      "toolIds": [
        "semgrep",
        "codeql"
      ],
      "blocksOn": "Rule matches in changed code",
      "note": "Semgrep with the p/ci ruleset and metrics turned off is a fast default. CodeQL goes deeper where you can run it."
    },
    {
      "stage": "Secrets",
      "toolIds": [
        "gitleaks"
      ],
      "blocksOn": "Any match not in the baseline or ignore file",
      "note": "Check out with fetch-depth: 0 so the scan sees every commit in the PR, not only the last one. Redact matches in logs."
    },
    {
      "stage": "Malicious packages",
      "toolIds": [
        "socket-cli"
      ],
      "blocksOn": "Install scripts, network access, obfuscation or known malware in new dependencies",
      "note": "Catches what has no CVE yet. Socket needs an API key, so make the step skip with a warning when the secret is missing (it is on fork PRs)."
    },
    {
      "stage": "IaC and pipeline",
      "toolIds": [
        "checkov",
        "poutine"
      ],
      "blocksOn": "Misconfigured Terraform, Dockerfiles and build pipelines",
      "note": "Opt-in per repository. Only worth the minutes where there is IaC or a complex release pipeline."
    },
    {
      "stage": "Gate",
      "toolIds": [],
      "blocksOn": "Any blocking stage above",
      "note": "Every scanner runs with continue-on-error so one failure doesn't hide the others. A PR comment summarizes them, then a single last step fails the check."
    }
  ]
}
