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 examplemain-a1b2c3d. - Three setup steps. Create a secret key with the scopes
scans:triggerandscans:read, store it asSAFEGUARD_API_KEYin 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-ona severity, or--fail-on-gatea 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-onyet. - 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 --helpfor 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.
| Guide | Read it when |
|---|---|
| Add Safeguard to GitHub Actions | Your code lives on GitHub and builds in Actions |
| Add Safeguard to GitLab CI | You run GitLab.com or a self-managed GitLab |
| Add Safeguard to Jenkins pipelines | You build in Jenkins, multibranch or single branch |
| Add Safeguard to Azure Pipelines | You build in Azure DevOps, from Azure Repos, GitHub or Bitbucket |
| Add Safeguard to Bitbucket Pipelines | You build in Bitbucket Cloud |
| Policy gates in CI: Block, Warn, Notify, exceptions and break-glass | You want the build to fail on your rules, not only on a severity |
| Scan modes in the pipeline: fast, deep, progressive | Pull request scans feel slow, or release scans feel shallow |
| SBOMs per release in CI: generate, attest, publish and diff | Customers or regulators ask for an SBOM per release |
| Scan container images in CI before push and deploy | Your 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:
| Mode | Command | Needs | Scans |
|---|---|---|---|
| On Safeguard (default) | safeguard ci scan | The repository connected as an integration, or public on github.com, gitlab.com or bitbucket.org | SAST, SBOM, dependency vulnerabilities |
| On the runner | safeguard ci scan --local | A checkout in the job; no integration | SBOM, 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
| Flag | Fails the step when |
|---|---|
--wait | The 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 system | Config file in the docs | Where SAFEGUARD_API_KEY lives | How branches are chosen | Fork or untrusted builds | Guide |
|---|---|---|---|---|---|
| GitHub Actions | .github/workflows/safeguard.yml | Settings, Secrets and variables, Actions (repository or organisation secret) | on.push.branches and on.pull_request.branches | GitHub passes no secrets to fork pull requests | GitHub Actions |
| GitLab CI/CD | .gitlab-ci.yml (include template or a plain job) | Settings, CI/CD, Variables, with Mask variable on | SAFEGUARD_BRANCH_PATTERN and SAFEGUARD_SCAN_MERGE_REQUESTS, or your own rules | A protected variable reaches only protected branches and tags | GitLab CI |
| Jenkins | Jenkinsfile stage | Manage Jenkins, Credentials, Secret text with ID safeguard-api-key | A when block with branch pattern and changeRequest target (multibranch only) | Depends on your multibranch source settings | Jenkins |
| Azure Pipelines | azure-pipelines.yml | Pipeline Variables with Keep this value secret on, or a variable group; mapped through env | trigger.branches.include and pr.branches.include | Secrets not passed to fork builds unless allowed | Azure Pipelines |
| Bitbucket Pipelines | bitbucket-pipelines.yml | Repository variables with Secured on, or a workspace variable | pipelines.branches and pull-requests | Secured variables not passed to fork pull requests | Bitbucket Pipelines |
| Any other CI | Your CI's own file | Your CI's secret store | Your CI's own triggers | Your CI's own rules | This 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@v4before 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 usingpull_request_targetwith 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/*andgithub/*.
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-scanjob in theteststage, 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_ONsets the severity (empty means no severity gate),SAFEGUARD_TIMEOUTdefaults to 30m,SAFEGUARD_PROJECTnames the project,SAFEGUARD_LOCALset to"true"scans on the runner, andSAFEGUARD_VERSIONpins the CLI. - Branch selection by regular expression.
SAFEGUARD_BRANCH_PATTERNdefaults to every branch;SAFEGUARD_SCAN_MERGE_REQUESTSset 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_REQUIREDon merge requests. - No test stage, no job. If your pipeline has no
teststage, the template's job never appears. Setstage: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 toSAFEGUARD_API_KEYwithwithCredentials. 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
whenblock usesbranch patternandchangeRequest target, which only match in a multibranch pipeline where Jenkins knows the branch. In a freestyle or plain pipeline job, delete thewhenblock: every build is scanned and the branch comes fromGIT_BRANCH. - Repository details come from the Git plugin. The CLI reads
GIT_URL,GIT_COMMITandBRANCH_NAME(orGIT_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
--localis 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 anenv:block. If you skip it, the step fails withAUTHENTICATION_REQUIRED. - Azure Repos ignores the
prblock. For repositories hosted in Azure Repos, pull request validation comes from a Build validation branch policy on the target branch, not frompr:in YAML. For GitHub and Bitbucket repositories built in Azure Pipelines, theprblock works as written. - Fork builds. Secrets are not passed to fork builds unless you allow it in the pipeline's trigger settings.
- Use
pr: noneto scan pushes only. Wildcards such asrelease/*work in bothtriggerandpr.
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
definitionsand reuses it formainand for pull requests. It runs on a smallalpineimage, so no Pipe or extra image is needed. - One
definitionsand onepipelineskey. 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:
| Action | When the policy fails |
|---|---|
| Block | The gate fails |
| Warn | The gate still passes, with a warning that names the policy |
| Notify | The 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 scanproduces 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.
- 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.
- Pick the scan location per repository. Default mode (with SAST) where Safeguard can reach the repository;
--localwhere source must stay on your network. - Connect the default mode repositories through the source control cards under Integrations, choosing the default scan mode as you connect.
- Create one secret key per project with only
scans:triggerandscans:read, locked to that project. - Store it as
SAFEGUARD_API_KEY, minding each platform's quirk from the map table. - Prepare a reviewed, pinned installer and make every pipeline use it.
- Add the step in report only mode. Run
safeguard ci scan --waitwithout--fail-onfor a week or two to learn which repositories would fail. - Turn on
--fail-on criticalon main and release branches, then on pull requests once teams can keep up. - 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>. - Add image steps for every pipeline that builds images, one per environment.
- Set up the release SBOM flow: keep, publish and diff an SBOM per release.
- 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 situation | Mode | Failure rule to start with | Guide to open |
|---|---|---|---|
| Cloud hosted Git, repository connected to Safeguard | Default (on Safeguard), includes SAST | --fail-on critical on main, report only on pull requests | Your CI's guide |
| Self-hosted or firewalled Git server | --local | --fail-on critical | Your CI's guide, plus CLI or local runner |
| Rules beyond severity (licenses, age, EPSS) | Either | --fail-on-gate <gate> with outcomes on | Policy gates in CI |
| Pull request scans are too slow | Fast on pull requests, deep on main | Unchanged | Scan modes |
| Customers ask for an SBOM per release | Either, on release branches or tags | Gate the release | SBOMs per release |
| The pipeline builds container images | --image step after build | --fail-on critical in prod only | Container images in CI |
| You need files to archive or post elsewhere | safeguard scan --dir . --output out/ on the build machine | Your own check on the output files | This post, FAQ |
| CI system not in the list | safeguard ci scan with --repository-url, --branch, --commit | --fail-on critical | This post, "Any other CI" |
Requirement versus what Safeguard does versus what you still own
| Requirement or risk | What Safeguard does in the pipeline | What 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 tag | Deciding 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 gate | Choosing 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 trail | Making 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 project | Storing, masking, protecting and rotating the key in your CI |
| Artifact integrity (OWASP CICD-SEC-9) | Attestations signed with Safeguard's key, verifiable with cosign | Signing 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 moment | Reviewing 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 app | Retaining CI logs, and connecting alerts to an owner |
| Code level flaws | SAST (GA) in the default mode, shown in Safeguard | Gating 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_KEYfor 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 ratepull_request_targetas High (SG-CICD-002) and untrusted event data in arun: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.
- 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.
- 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.
- 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-onyet. The--localmode does not include SAST at all. - It does not evaluate policies inside the CLI. Gates are evaluated in the platform.
--fail-on-gateneeds policy outcomes turned on for your workspace, which Safeguard does per workspace, and it needs network access to Safeguard from the runner. - 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.
- 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.
- 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.
- 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 situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull 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
- Safeguard docs: CI/CD Integration
- Safeguard docs: GitHub Actions
- Safeguard docs: GitLab CI/CD
- Safeguard docs: Jenkins
- Safeguard docs: Azure Pipelines
- Safeguard docs: Bitbucket Pipelines
- Safeguard docs: Container images in CI
- Safeguard docs: CI/CD Security
- Safeguard docs: CLI
- Safeguard docs: CLI installation
- Safeguard docs: CLI usage
- Safeguard docs: Policies and gates
- Safeguard docs: Policy outcomes and actions
- Safeguard docs: Attestation and signing
- Safeguard docs: GitHub integration
- Safeguard docs: GitLab integration
- Safeguard docs: Portal SBOM repository
- NIST SP 800-204D: Strategies for the Integration of Software Supply Chain Security in DevSecOps CI/CD Pipelines
- NIST SP 800-218: Secure Software Development Framework
- OWASP Top 10 CI/CD Security Risks
- SLSA v1.0: Security levels
- SLSA v1.0: Threats and mitigations
- CycloneDX specification overview
- OpenSSF Scorecard checks
- GitHub Docs: Security hardening for GitHub Actions
- GitHub Docs: Events that trigger workflows
- GitLab Docs: CI/CD variables
- Jenkins: Using credentials
- Microsoft Learn: Set secret variables in Azure Pipelines
- Atlassian: Bitbucket Pipelines variables and secrets
Last reviewed: 25 October 2026. Product capabilities change; check docs.safeguard.sh for the current state.