Safeguard
Product•

CI/CD Security with Safeguard: A Pipeline-by-Pipeline Map

Safeguard runs one shell step, safeguard ci scan, in GitHub Actions, GitLab, Jenkins, Azure or Bitbucket. This map links each setup, gate and SBOM guide.

Safeguard Security Team
39 min read

Safeguard adds supply chain security to a CI/CD pipeline with one shell step that runs safeguard ci scan. The same command works in GitHub Actions, GitLab CI/CD, Jenkins, Azure Pipelines, Bitbucket Pipelines and any CI that can run bash, and it can fail the build on a severity threshold or on a Safeguard policy gate. This post is the map: what every pipeline has in common, what differs per CI system, and which detailed guide to open next.

There is no plugin, Action or Pipe to install: Safeguard's CI/CD Integration docs say every system runs the CLI in a plain shell step on a Linux or macOS runner. So the command, the secret key and the failure rules are the same everywhere. Only the file, the secret store, the trigger syntax and a few quirks change.

Key takeaways

  • One command everywhere. safeguard ci scan (CLI in CI, GA) runs as a shell step. Each push becomes a new version of its Safeguard project, named after the branch and commit, for example main-a1b2c3d.
  • Three setup steps. Create a secret key with the scopes scans:trigger and scans:read, store it as SAFEGUARD_API_KEY in your CI, add the step from your CI's guide.
  • Two places the scan can run. On Safeguard (the default, which covers SAST, SBOM and dependency vulnerabilities) or on the runner with --local (SBOM and dependency vulnerabilities, and only results leave the runner).
  • Two ways to fail a build. --fail-on a severity, or --fail-on-gate a Safeguard policy gate (policies and gates, GA). Gate actions are Block, Warn and Notify. A Block is passed only through an approved exception.
  • SAST findings do not fail builds yet. SAST (GA) runs in the on-Safeguard mode and its findings show in Safeguard, but the docs say they are not part of --fail-on yet.
  • Images get their own step. safeguard ci scan --image (container scanning, GA) scans the built image on the runner and records one version per environment and tag.
  • SBOMs and attestation. Every scan produces an SBOM (SBOM generation and analysis, GA). Attestations (attestation and signing, GA) are signed with Safeguard's key and verifiable with cosign; there is no public transparency log, and no CLI command for signing yet.
  • Fixes stay human controlled. Autonomous remediation (GA) opens fix pull requests, but it ships switched off with every category set to Manual.
  • Snippets in this post come from docs.safeguard.sh, fetched on 25 October 2026. We did not run them. Check them against safeguard ci scan --help for the CLI version you pin.

How to use this map

Each CI system and each cross cutting topic has its own detailed guide with the full YAML and troubleshooting. This hub summarises each one and what is different about it, so you can decide where to start.

GuideRead it when
Add Safeguard to GitHub ActionsYour code lives on GitHub and builds in Actions
Add Safeguard to GitLab CIYou run GitLab.com or a self-managed GitLab
Add Safeguard to Jenkins pipelinesYou build in Jenkins, multibranch or single branch
Add Safeguard to Azure PipelinesYou build in Azure DevOps, from Azure Repos, GitHub or Bitbucket
Add Safeguard to Bitbucket PipelinesYou build in Bitbucket Cloud
Policy gates in CI: Block, Warn, Notify, exceptions and break-glassYou want the build to fail on your rules, not only on a severity
Scan modes in the pipeline: fast, deep, progressivePull request scans feel slow, or release scans feel shallow
SBOMs per release in CI: generate, attest, publish and diffCustomers or regulators ask for an SBOM per release
Scan container images in CI before push and deployYour pipeline builds and ships images

If you are new to the product, two earlier posts set the scene: how to choose between the CLI and the local runner, and how plain English policies become release gates.

The problem: pipelines are where supply chain risk turns into a release

A CI/CD pipeline is the last automated step between a dependency change and a shipped product. Whatever it lets through becomes your release. Without a supply chain check in the pipeline, three things tend to go wrong.

Vulnerable dependencies ship without anyone deciding to ship them. A developer bumps a framework, a lockfile pulls in a new transitive package, and the build goes green because nothing in it looks at what was resolved. The OWASP Top 10 CI/CD Security Risks project lists this family of problems as CICD-SEC-3, Dependency Chain Abuse, and treats the build system's handling of third party code as a core risk, not an edge case.

Nobody can say what was in a given release. When a new advisory lands, the question is which versions of which products contain the affected component. If the pipeline did not record an inventory per build, the answer is a manual search through old artifacts. OWASP's CICD-SEC-9, Improper Artifact Integrity Validation, and CICD-SEC-10, Insufficient Logging and Visibility, both describe the cost of not knowing what a pipeline produced.

Security rules live in a wiki, not in the build. Many teams have a written rule like "no critical vulnerabilities in production". Without a gate, the rule depends on someone remembering to check. OWASP's CICD-SEC-1, Insufficient Flow Control Mechanisms, is about exactly this: a pipeline that lets code reach production without enforced checks.

What the standards ask for

The guidance is consistent across standards bodies, even if the wording differs.

  • NIST SP 800-218, the Secure Software Development Framework (SSDF), published in February 2022, recommends a core set of secure development practices that software producers integrate into whatever life cycle they already use. Its stated aims include reducing vulnerabilities in released software and addressing their root causes. A pipeline step that scans every build and records what was found is one of the most direct ways to show those practices running, rather than described.
  • NIST SP 800-204D, published in February 2024, is specifically about integrating software supply chain security measures into DevSecOps CI/CD pipelines. Its abstract describes the pipeline stages (build, test, package, deploy) as operations that make up the software supply chain. That framing is the one this post uses: each stage is a checkpoint.
  • SLSA v1.0 defines a Build track whose first level, L1, is simply "provenance exists": a record of how an artifact was built. A per commit SBOM and scan is the evidence that work starts from.
  • The CycloneDX specification describes a machine readable bill of materials, so a customer or auditor can answer "what is in this release" without asking you.
  • The OpenSSF Scorecard checks include Pinned-Dependencies, Dangerous-Workflow and Token-Permissions, a reminder that the CI file is code with its own supply chain.

None of these documents require a product. They describe outcomes: know what you ship, check it before it ships, keep the record.

The one pattern every pipeline shares

Every guide in this series is a variation of the same pattern. If you understand these five parts, the per platform guides become a matter of syntax.

1. A secret key with two scopes

Create a secret key in Safeguard under Settings, then Developer, with the scopes scans:trigger and scans:read. The docs note you can lock the key to one project. In the app, an admin can also create one from the Set up CI/CD sheet.

Locking the key to one project matters more than it looks. A CI secret is readable by anyone who can change the pipeline file on a branch that receives it. A key that can only trigger and read scans for one project limits what a leaked key can do, which is the point of OWASP's CICD-SEC-6, Insufficient Credential Hygiene.

2. The secret stored as SAFEGUARD_API_KEY

Every CI system has its own secret store, and each guide says where. The name is always SAFEGUARD_API_KEY. The safeguard ci scan command reads that variable. The CLI's interactive commands sign in differently, through safeguard login, so do not expect a developer's local sign in to carry over to CI, or the CI key to work for interactive use.

3. One step that runs the scan

The core command, as every CI guide in the docs shows it:

safeguard ci scan --wait --fail-on critical

The first run creates the Safeguard project, so nothing else is needed to start. Each push becomes a new version of that project, named <branch>-<commit>. On a pull request or merge request, the source branch is scanned and its head commit names the version.

4. A choice of where the scan runs

The CI/CD Integration docs describe two modes:

ModeCommandNeedsScans
On Safeguard (default)safeguard ci scanThe repository connected as an integration, or public on github.com, gitlab.com or bitbucket.orgSAST, SBOM, dependency vulnerabilities
On the runnersafeguard ci scan --localA checkout in the job; no integrationSBOM, dependency vulnerabilities

With --local, only the results leave the runner. The docs point out that this makes it work for self-hosted and firewalled Git servers too. It reads dependencies from lockfiles and manifests such as package-lock.json, go.sum, requirements.txt and pom.xml.

The trade-off is coverage. The on-Safeguard mode includes SAST (GA); the runner mode does not. If your source cannot leave your network, --local gives you the SBOM and dependency findings, and SAST needs a different route, for example the local runner, which executes the platform's scan jobs on your own machine and sends only results.

5. A rule for failing the build

FlagFails the step when
--waitThe scan fails or takes longer than --timeout (default 30m)
--fail-on <severity>With --wait: a dependency vulnerability at or above critical, high, medium or low
--fail-on-gate <gate>With --wait: a policy gate (its name, id, or all) is not Passed or Warning

Drop --fail-on to report without failing. The two failure flags can be combined.

That is the whole pattern. Everything else in the per platform guides is about where the secret lives, how the trigger is written and which quirks bite.

Installing the CLI in a pipeline without piping a script into a shell

Each CI template in Safeguard's docs installs the CLI with a one line installer fetched from cli.safeguard.sh. The installer verifies the download against the release's published checksums and refuses to install on a mismatch (the macOS and Linux installer fails closed; the Windows one warns and continues).

Even so, we recommend you do not pipe a script from the internet straight into a shell in your pipeline. Safeguard's own docs agree. The installation page says "never pipe a URL you have not read into a shell", and the CI/CD Security docs list a download piped into a shell as a High severity pipeline finding (rule SG-CICD-005), with the advice to download, verify, then run installers.

The installation docs show the read first form:

curl -fsSL https://cli.safeguard.sh/install -o install.sh && less install.sh
bash install.sh

In a pipeline, read the installer once on a workstation, keep the copy you read in your repository or an internal artifact store, and have the pipeline run that reviewed file with bash. Then pin the release: both installers read SAFEGUARD_VERSION (install this exact release) and SAFEGUARD_INSTALL_DIR (put the binary here); the CLI installation docs explain how to find the release to pin. Without a pin, the installer resolves the newest release on every run, so two builds of the same commit can behave differently. More in pin the Safeguard CLI version in CI.

The map: every CI system at a glance

This table is the whole series on one screen. The detail is in each guide.

CI systemConfig file in the docsWhere SAFEGUARD_API_KEY livesHow branches are chosenFork or untrusted buildsGuide
GitHub Actions.github/workflows/safeguard.ymlSettings, Secrets and variables, Actions (repository or organisation secret)on.push.branches and on.pull_request.branchesGitHub passes no secrets to fork pull requestsGitHub Actions
GitLab CI/CD.gitlab-ci.yml (include template or a plain job)Settings, CI/CD, Variables, with Mask variable onSAFEGUARD_BRANCH_PATTERN and SAFEGUARD_SCAN_MERGE_REQUESTS, or your own rulesA protected variable reaches only protected branches and tagsGitLab CI
JenkinsJenkinsfile stageManage Jenkins, Credentials, Secret text with ID safeguard-api-keyA when block with branch pattern and changeRequest target (multibranch only)Depends on your multibranch source settingsJenkins
Azure Pipelinesazure-pipelines.ymlPipeline Variables with Keep this value secret on, or a variable group; mapped through envtrigger.branches.include and pr.branches.includeSecrets not passed to fork builds unless allowedAzure Pipelines
Bitbucket Pipelinesbitbucket-pipelines.ymlRepository variables with Secured on, or a workspace variablepipelines.branches and pull-requestsSecured variables not passed to fork pull requestsBitbucket Pipelines
Any other CIYour CI's own fileYour CI's secret storeYour CI's own triggersYour CI's own rulesThis post, "Any other CI" below

In the Safeguard app there is also a shortcut. The GitHub, GitLab, Bitbucket and Azure DevOps cards under Integrations, Source Control have a Set up CI/CD button, and the Git card has one for Jenkins and any other CI. It opens the setup with your branches and severity filled in. A project's own Set up CI/CD button does the same with that project's id.

Pipeline by pipeline

GitHub Actions

What the guide covers. Add Safeguard to GitHub Actions walks through the documented workflow file, a single job with one step on ubuntu-latest, triggered on pushes to main and pull requests into it. It adds the hosted, runner and build machine variants, monorepos with several projects, and moving to a policy gate.

What is different on GitHub.

  • No checkout is needed for the default mode. Safeguard clones the repository itself. Add actions/checkout@v4 before the step only when you switch to --local.
  • Fork pull requests get no secrets. GitHub's own docs state that, apart from GITHUB_TOKEN, secrets are not passed to the runner when a workflow is triggered from a forked repository. So a Safeguard step on a fork pull request fails to authenticate. The Safeguard docs suggest scanning pushes only, or using pull_request_target with care, because it runs with your secrets and you must never run the fork's code in that job.
  • Pin third party actions by commit. GitHub's security hardening guide recommends pinning actions to a full length commit SHA. Safeguard's own CI/CD Security rule SG-CICD-001 flags third party actions pinned to a tag or branch for the same reason, and does not flag GitHub's own actions/* and github/*.

Options the docs list. --fail-on high (or medium, low) for another threshold, --fail-on-gate all to fail on a policy gate, --project-id <id> for a specific project, and SAFEGUARD_VERSION in env to pin the CLI.

There is also a shorter getting started guide for a GitHub Actions gate. For the connection side (repositories, pull request checks and fix pull requests), see connect Safeguard to GitHub and connect GitHub to Safeguard: repositories, pull request checks and fix PRs.

GitLab CI/CD

What the guide covers. Add Safeguard to GitLab CI covers the merge request job, where the SBOM lives, policy gates, image scans, self-managed GitLab, scheduled pipelines and a complete .gitlab-ci.yml.

What is different on GitLab.

  • Two documented ways to add the job. The docs offer a Safeguard template you include, which defines a hidden .safeguard-scan job in the test stage, and a plain job written without the template. With the template, behaviour is controlled by variables rather than flags.
  • Variables instead of flags. With the template, SAFEGUARD_FAIL_ON sets the severity (empty means no severity gate), SAFEGUARD_TIMEOUT defaults to 30m, SAFEGUARD_PROJECT names the project, SAFEGUARD_LOCAL set to "true" scans on the runner, and SAFEGUARD_VERSION pins the CLI.
  • Branch selection by regular expression. SAFEGUARD_BRANCH_PATTERN defaults to every branch; SAFEGUARD_SCAN_MERGE_REQUESTS set to "false" skips merge request pipelines.
  • The protected variable trap. GitLab's docs say a protected variable is only available in pipelines that run on protected branches or protected tags. Safeguard's docs therefore tell you to leave Protect variable off if unprotected branches or merge requests should be scanned. The symptom, if you forget, is AUTHENTICATION_REQUIRED on merge requests.
  • No test stage, no job. If your pipeline has no test stage, the template's job never appears. Set stage: on the job.

For the integration side, see connect Safeguard to GitLab and connect GitLab to Safeguard: projects, merge request checks and fix MRs. The GitLab integration docs note that, with write access, Safeguard can also open fix merge requests, comment on merge requests and set a commit status for the quality gate.

Jenkins

What the guide covers. Add Safeguard to Jenkins pipelines is built around one declarative stage in a multibranch pipeline, with a checklist, branch selection, options, policy gates, SBOMs, image scans and signing.

What is different on Jenkins.

  • The credential is Secret text. Store the key under Manage Jenkins, Credentials, as a Secret text credential with the ID safeguard-api-key, and bind it to SAFEGUARD_API_KEY with withCredentials. Jenkins' own credentials docs describe Secret text as the type for a token such as an API token.
  • Branch filtering needs a multibranch pipeline. The documented when block uses branch pattern and changeRequest target, which only match in a multibranch pipeline where Jenkins knows the branch. In a freestyle or plain pipeline job, delete the when block: every build is scanned and the branch comes from GIT_BRANCH.
  • Repository details come from the Git plugin. The CLI reads GIT_URL, GIT_COMMIT and BRANCH_NAME (or GIT_BRANCH).
  • No Windows agents. The agent needs Linux or macOS with curl. The docs say Windows agents are not supported.
  • The workspace already has the checkout. So switching to --local is a one flag change.

The most common Jenkins failure, per the docs, is a stage that is always skipped. That is a single branch job with a when block that can never match.

Azure Pipelines

What the guide covers. Add Safeguard to Azure Pipelines covers the YAML step, policy gates, image scans, SBOM files as pipeline artifacts, attestation and what to do after a gate fails.

What is different on Azure Pipelines.

  • Secrets must be mapped through env. Microsoft's docs say secret variables are not automatically decrypted into environment variables for scripts; you map them explicitly. The Safeguard step does that with an env: block. If you skip it, the step fails with AUTHENTICATION_REQUIRED.
  • Azure Repos ignores the pr block. For repositories hosted in Azure Repos, pull request validation comes from a Build validation branch policy on the target branch, not from pr: in YAML. For GitHub and Bitbucket repositories built in Azure Pipelines, the pr block works as written.
  • Fork builds. Secrets are not passed to fork builds unless you allow it in the pipeline's trigger settings.
  • Use pr: none to scan pushes only. Wildcards such as release/* work in both trigger and pr.

Note the difference between Azure Pipelines (the CI system covered here) and the Azure DevOps source control integration in Safeguard, which connects repositories so the on-Safeguard mode can clone them.

Bitbucket Pipelines

What the guide covers. Add Safeguard to Bitbucket Pipelines explains the step definition, policy gates, options, keeping SBOM files with the build, fix pull requests, signing and troubleshooting.

What is different on Bitbucket.

  • A reusable step anchor. The documented file defines the step once under definitions and reuses it for main and for pull requests. It runs on a small alpine image, so no Pipe or extra image is needed.
  • One definitions and one pipelines key. Bitbucket allows only one of each. If you already have a file, merge the step in rather than appending a second copy; otherwise the file does not validate.
  • Pull request patterns match the source branch. The docs point out that pull-requests: '**' scans every pull request whatever its target, because Bitbucket matches the pattern against the source branch and cannot filter by target.
  • Secured variables and forks. Atlassian's docs describe secured variables as values that cannot be edited, only replaced or deleted. Safeguard's docs add that they are not passed to fork pull requests.

Any other CI

Any CI that runs a shell step works. When your CI is not one of the five above, pass the repository, branch and commit yourself. The docs show the command shape:

SAFEGUARD_API_KEY=... safeguard ci scan --wait --fail-on critical \
  --repository-url "$REPO_URL" --branch "$BRANCH" --commit "$COMMIT"

The docs note that CircleCI is detected too, so on CircleCI you may not need to pass all three. Install the CLI the same way as above: a reviewed, pinned installer rather than a pipe into a shell. Never put the key itself on the command line in a committed file; set SAFEGUARD_API_KEY from your CI's secret store.

Cross cutting topics: the four guides that apply to every pipeline

The platform guides add the step. These four, which apply to every CI system, cover what to do with it.

Policy gates: Block, Warn, Notify and exceptions

What the guide covers. Policy gates in CI with Safeguard covers how a gate decides, configuration for each CI system, where gates belong, exceptions, an emergency procedure you design around them, and what happens when a gate cannot decide.

The short version. Policies and gates (GA) are evaluated in the platform, not by the CLI. Each policy has one Action that decides what a failed policy does to the gate:

ActionWhen the policy fails
BlockThe gate fails
WarnThe gate still passes, with a warning that names the policy
NotifyThe gate still passes, and Safeguard notifies your workspace's configured channels

A gate's outcome follows a fixed order in the Policy outcomes docs: any failed Block policy makes the gate Failed; otherwise any policy that could not be evaluated makes it Error; otherwise any policy not yet evaluated makes it Not evaluated; otherwise a failed Warn policy makes it Warning; otherwise it is Passed. An Error is never counted as a pass.

In CI, safeguard ci scan --wait --fail-on-gate <gate name or id | all> waits for the scan and for the gate's policies to be evaluated on the new data. It exits 0 when the gate is Passed or Warning, and non zero when the gate is Failed, Error or Not evaluated, or when evaluation does not finish before --timeout.

Exceptions are how a Block is passed. The Policies & Gates docs describe the workflow: a developer requests an exception, selects the policy and finding, gives a business justification and an expiration date, approvers are notified and decide, and an audit trail is recorded. Approval happens in that exception workflow.

One prerequisite. Policy outcomes are turned on per workspace by Safeguard. If your Gates and Policies tables do not show an Outcome column, ask your Safeguard contact to turn it on. Until then, --fail-on <severity> is the failure rule you can rely on.

What a gate can check. The Policies & Gates docs list conditions such as vulnerability severity, CVSS score, EPSS score, license, component age, maintenance and SLSA level, and templates such as No Critical Vulnerabilities and License Compliance. CISA KEV status is available as a filter when you prioritise findings, but the docs do not list it as a gate condition, so do not design a gate that depends on it. For how reachability, EPSS and KEV feed prioritisation, see prioritise vulnerabilities with reachability, EPSS and KEV in Safeguard.

Scan modes per trigger

What the guide covers. Scan modes in the pipeline sets out the three scan modes, fast, deep and progressive (scan modes, GA), with a decision table for which mode suits which trigger, step by step configuration for all five CI systems, what to expect from a progressive scan on a schedule, how to wire the release gate, and how to roll it out without breaking builds.

The short version. The Safeguard integration docs offer the modes when you connect a repository: the GitHub Connect button's menu reads "Connect: Fast scan (quicker)", "Connect: Deep scan (full)" and "Connect: Progressive scan (fast now, full depth after)", and the GitLab guide offers the same three. The common pattern is fast feedback on pull requests and full depth on main and releases.

The CI/CD Integration docs page does not list a scan mode flag for safeguard ci scan at the time of writing. The scan modes guide explains how to check what your pinned CLI version supports with safeguard ci scan --help. The CLI usage docs say that when the docs page and --help disagree, --help is right.

SBOMs per release: generate, attest, publish and diff

What the guide covers. SBOMs per release in CI is a seven step release flow: decide what a release is to your pipeline, generate the release SBOM, gate the release, keep a file copy, attest and sign, publish in Portal, and diff one release against the last.

The short version.

  • Generate. Every safeguard ci scan produces an SBOM for that version (SBOM generation and analysis, GA). If you also want files you keep as build artifacts, safeguard scan --dir . --output out/ writes JSON results under the output folder.
  • Attest. Per Safeguard's Attestation and Signing docs, every attestation Safeguard produces is signed with Safeguard's own key, held in a cloud key management service, and verified with cosign against Safeguard's published public key. Signatures are not written to a public transparency log, which is why the documented cosign commands pass --insecure-ignore-tlog. The same docs say there is no CLI command for signing yet, and no CLI command for verifying or listing attestations yet; attestation records appear on the Attestation tab in the app. Any signature you put on a file you ship is your own signing step with your own key.
  • Publish. Portal (GA) stores SBOMs as product versions you can share with customers. The publish versus share post explains the difference.
  • Diff. The Portal SBOM repository docs describe Compare: pick two versions and see added components, removed components, version changes, new vulnerabilities and resolved vulnerabilities.

For the standards side of SBOM content, see SBOM generation and analysis in Safeguard, and for how attestation scores work, attestation and provenance in Safeguard.

Container images before push and deploy

What the guide covers. Scan container images in CI shows build, scan, then push on every CI system, policy gates, deploying the exact bytes you scanned by digest, and rescanning at deploy time.

The short version. Add one step after the image is built:

safeguard ci scan --image "ghcr.io/acme/api:$TAG" --environment prod --wait --fail-on critical

The image is scanned on the runner (container scanning, GA) and recorded under the image's repository, one version per environment and tag, such as prod-1.4.2. A latest or missing tag uses the build's commit instead. The image is read from the local Docker daemon when the step runs where it was built; otherwise set SAFEGUARD_REGISTRY_USERNAME and SAFEGUARD_REGISTRY_PASSWORD as CI secrets so the scan can pull it. Only the results leave the runner, and no repository integration is needed.

Use one step per environment, each with its own --environment. That lets you fail where it matters, for example --fail-on critical in production and no --fail-on in development. Every container registry card under Integrations in the app has a Set up CI/CD button that produces these steps for your CI, image and environments.

For how images are tracked per environment once they are in Safeguard, see track container images per environment.

Step by step: rolling Safeguard out across every pipeline

Most organisations run more than one CI system. This order of work has the fewest surprises.

  1. List your pipelines. One row per repository: CI system, where the source lives, whether it builds images, and the owner. This becomes your coverage evidence.
  2. Pick the scan location per repository. Default mode (with SAST) where Safeguard can reach the repository; --local where source must stay on your network.
  3. Connect the default mode repositories through the source control cards under Integrations, choosing the default scan mode as you connect.
  4. Create one secret key per project with only scans:trigger and scans:read, locked to that project.
  5. Store it as SAFEGUARD_API_KEY, minding each platform's quirk from the map table.
  6. Prepare a reviewed, pinned installer and make every pipeline use it.
  7. Add the step in report only mode. Run safeguard ci scan --wait without --fail-on for a week or two to learn which repositories would fail.
  8. Turn on --fail-on critical on main and release branches, then on pull requests once teams can keep up.
  9. Move to a policy gate. Link your policies to a gate, choose Block, Warn or Notify for each, confirm policy outcomes are on, and switch to --fail-on-gate <gate>.
  10. Add image steps for every pipeline that builds images, one per environment.
  11. Set up the release SBOM flow: keep, publish and diff an SBOM per release.
  12. Turn on autonomous remediation category by category, if you want it. It ships switched off, with every category set to Manual.

Do steps 1 to 7 everywhere before step 8 anywhere. Report only on every pipeline beats a hard gate on one.

Decision table: which setup for which pipeline

Your situationModeFailure rule to start withGuide to open
Cloud hosted Git, repository connected to SafeguardDefault (on Safeguard), includes SAST--fail-on critical on main, report only on pull requestsYour CI's guide
Self-hosted or firewalled Git server--local--fail-on criticalYour CI's guide, plus CLI or local runner
Rules beyond severity (licenses, age, EPSS)Either--fail-on-gate <gate> with outcomes onPolicy gates in CI
Pull request scans are too slowFast on pull requests, deep on mainUnchangedScan modes
Customers ask for an SBOM per releaseEither, on release branches or tagsGate the releaseSBOMs per release
The pipeline builds container images--image step after build--fail-on critical in prod onlyContainer images in CI
You need files to archive or post elsewheresafeguard scan --dir . --output out/ on the build machineYour own check on the output filesThis post, FAQ
CI system not in the listsafeguard ci scan with --repository-url, --branch, --commit--fail-on criticalThis post, "Any other CI"

Requirement versus what Safeguard does versus what you still own

Requirement or riskWhat Safeguard does in the pipelineWhat you still own
Know what each build contains (CycloneDX and SPDX SBOMs, SLSA provenance starts here)One SBOM per scanned version, named after branch and commit or environment and tagDeciding which builds are releases, and keeping your release record
Stop known vulnerable dependencies (OWASP CICD-SEC-3)Fails the step on a severity threshold or a policy gateChoosing thresholds, fixing or excepting what fails
Enforced flow control (OWASP CICD-SEC-1)Gate outcome with Block, Warn and Notify, and an exception workflow with an audit trailMaking the CI job a required check in your source control, and who may bypass it
Credential hygiene (OWASP CICD-SEC-6)Secret keys with narrow scopes, lockable to one projectStoring, masking, protecting and rotating the key in your CI
Artifact integrity (OWASP CICD-SEC-9)Attestations signed with Safeguard's key, verifiable with cosignSigning your own artifacts with your own key, and verifying at deploy
Pipeline configuration hygiene (pinning, token permissions)Safeguard's CI/CD Security checks are documented but not offered in the app at the momentReviewing your CI files, pinning actions, least privilege tokens
Visibility after the build (OWASP CICD-SEC-10)Versions, findings, gate outcomes and evaluation history in the appRetaining CI logs, and connecting alerts to an owner
Code level flawsSAST (GA) in the default mode, shown in SafeguardGating on SAST yourself until --fail-on covers it

Securing the scan step itself

A security step that weakens the pipeline is worse than no step. Three habits keep it safe.

  • Treat the key as a credential. Narrow scopes, one project per key, stored only in the CI secret store, masked in logs. If it leaks, revoke it and create a new one; the docs list INVALID_SECRET_KEY for a revoked or expired key.
  • Do not hand secrets to untrusted code. If you use GitHub's pull_request_target, never check out or run the fork's code in that job. Safeguard's CI/CD Security docs rate pull_request_target as High (SG-CICD-002) and untrusted event data in a run: step as Critical (SG-CICD-003).
  • Grant least privilege to the job. The same docs advise starting each job's permissions from contents: read.

Those CI/CD Security rules cover GitHub Actions workflow files and .gitlab-ci.yml. The docs say plainly that the checks are not offered in the app at the moment, and that Bitbucket, Jenkins and Azure Pipelines files are not checked yet. Use the rules as a checklist; do not expect the product to run them for you today.

What Safeguard does not do

Honest limits, from the docs as of 25 October 2026.

  1. It does not ship a plugin, Action, Orb or Pipe. Every CI system runs the CLI in a shell step. If your organisation only allows marketplace components in pipelines, plan for that review.
  2. It does not run on Windows CI agents. The docs require a Linux or macOS runner with bash and curl, and the Jenkins guide says Windows agents are not supported.
  3. It does not fail builds on SAST findings yet. SAST findings are scanned and shown in Safeguard in the default mode, but the docs say they are not part of --fail-on yet. The --local mode does not include SAST at all.
  4. It does not evaluate policies inside the CLI. Gates are evaluated in the platform. --fail-on-gate needs policy outcomes turned on for your workspace, which Safeguard does per workspace, and it needs network access to Safeguard from the runner.
  5. It does not sign your artifacts from the pipeline. There is no CLI command for signing yet, and no CLI command for verifying or listing attestations yet. Safeguard's attestations are signed with Safeguard's key and have no public transparency log entry.
  6. It does not check your pipeline configuration in the app today. The CI/CD Security checks are documented but not offered in the app at the moment.
  7. It does not make the CI job a required check. Branch protection, required status checks and who may bypass them are settings in your source control system.
  8. It does not fix things on its own by default. Autonomous remediation ships switched off, with every category set to Manual.

Common mistakes

Starting with a hard gate. --fail-on critical everywhere on day one turns a rollout into a build outage. Start in report only mode.

Piping the installer into a shell and not pinning it. It works, which is why it spreads. It also means a new CLI release can change a build between two runs of the same commit. Use a reviewed copy and SAFEGUARD_VERSION.

Forgetting env on Azure. Secret variables are not decrypted into the script's environment unless you map them. The step then fails with AUTHENTICATION_REQUIRED.

Keeping the when block in a single branch Jenkins job. The stage is skipped every time and nobody notices, because a skipped stage is green.

Appending a second definitions key in Bitbucket. The file stops validating. Merge the step into the existing keys.

Using --fail-on-gate before policy outcomes are on. The step cannot pass on a gate whose outcome is never evaluated. Check for the Outcome column first.

Granting exceptions without expiry. The exception workflow asks for an expiration date for a reason. An exception with no end is a permanent policy change that nobody reviewed as one.

Reusing image tags. The image version name comes from the environment and the tag, so use unique tags, such as the commit, for anything you deploy.

FAQ

How do I add Safeguard to my CI/CD pipeline?

Create a secret key under Settings, Developer with scans:trigger and scans:read, store it in your CI as SAFEGUARD_API_KEY, and add one shell step that installs the CLI and runs safeguard ci scan --wait --fail-on critical. The first run creates the project. Each CI system's guide in this series has the exact file.

Which CI systems does Safeguard support?

The docs have guides for GitHub Actions, GitLab CI/CD, Bitbucket Pipelines, Jenkins and Azure Pipelines, and say any CI that runs a shell step works, with the repository, branch and commit passed as flags. CircleCI is detected too. The runner must be Linux or macOS with bash and curl.

Is there a Safeguard GitHub Action or Jenkins plugin?

No. The docs say there is no plugin, Action or Pipe to install. Every system runs the CLI in a plain shell step.

Can Safeguard fail a build on a policy, not just on severity?

Yes. safeguard ci scan --wait --fail-on-gate <gate> fails the step when the gate is Failed, Error or Not evaluated, and passes on Passed or Warning. It needs policy outcomes turned on for your workspace. You can combine it with --fail-on.

Does my source code leave the pipeline?

In the default mode, Safeguard clones the repository through its integration and scans it on Safeguard. With --local, the scan runs on the runner and only results leave it. Image scans with --image also run on the runner and send only results.

Does Safeguard scan container images in CI?

Yes. Add safeguard ci scan --image <ref> --environment <name> after the build. It scans on the runner, records one version per environment and tag, and can fail on a severity. See the container images in CI guide.

How do I get SBOM files out of a pipeline run?

Every safeguard ci scan records an SBOM for that version in Safeguard. For files on the build machine, safeguard scan --dir . --output out/ writes JSON results. It does not fail on findings, so gate on the files it writes, as the docs show with jq. On a fresh runner it needs its scanner toolchain on the PATH, which the CLI docs describe.

Does Safeguard sign what my pipeline builds?

Not from the pipeline today. Safeguard's attestations are signed with Safeguard's key and verifiable with cosign, without a public transparency log entry. The docs say there is no CLI command for signing yet. Sign your own release artifacts with your own key.

The pipeline is where Safeguard stops a vulnerable dependency from shipping. The block below covers what happens after the gate fails and someone has to produce the fix, including when upstream has not released one.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.

3. Gold Registry: start from components that are already fixed

Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingSafeguard policies and gates in CI
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The CLI demo is a real session in the Safeguard interactive terminal: you ask it to fix the lodash CVE in a repository, and it reads the finding and the advisory, asks before any command that changes something, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. That is the developer's move after a pipeline gate fails: fix it locally, push, and let the same safeguard ci scan step run again.

Click through it at your own pace, or open it full screen.

The local runner demo sets up the runner on your own machine, approves it with its device code, then scans from the terminal. It is the closest match to the pipelines in this map that cannot send source code to Safeguard: the scan runs where the code is and only results leave.

Click through it at your own pace, or open it full screen.

To try this on your own pipelines, get the CLI from safeguard.sh/download and follow the CI/CD Integration guides in the Safeguard docs.

Quick check

Your GitLab pipeline scans main fine, but the Safeguard job fails with AUTHENTICATION_REQUIRED on every merge request. What is the most likely cause?

The SAFEGUARD_API_KEY variable has Protect variable turned on. GitLab only passes protected variables to pipelines on protected branches and tags, so merge request pipelines from unprotected branches get no key. Keep Mask variable on and turn Protect variable off if those pipelines should be scanned.

A pipeline runs safeguard ci scan with --local and --fail-on critical. Will a critical SAST finding fail the build?

No, for two reasons. The --local mode scans the SBOM and dependency vulnerabilities only, without SAST. And even in the default mode, where SAST runs, the docs say SAST findings are not part of --fail-on yet.

Sources

Last reviewed: 25 October 2026. Product capabilities change; check docs.safeguard.sh for the current state.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.