You manage vulnerabilities across repositories on different source control platforms by moving the program above the platforms. Build one inventory of every repository wherever it lives, scan all of them into one findings model with one ranking, write one baseline policy that every business unit inherits and may only tighten, keep one exception register, and onboard the estate in waves so no team gets a thousand alerts on the same morning. Each platform's built-in alerts can stay on for developers, but they stop being the program.
This post is for the platform engineering or application security lead at a company that grew by acquisition, or let teams pick their own tools, and now has repositories on two, three or four hosts. The method works with whatever scanners you run. Near the end we show how Safeguard does the same job, with the maturity label of every capability and of each source control integration as Safeguard's docs state it.
Key takeaways
- Native alerting on each platform gives a different view of the same risk: different advisory sources, severity labels, dismissal records and coverage. Three platforms means three programs.
- Start with inventory, not scanning. Enumerate repositories from every platform's API, reconcile them against CI, registries and deploy manifests, and keep one record per repository with an owner and a business unit.
- Map the organisation once (company, business unit, team, repository) and attach scope, roles and policy to that map, not to each platform's groups.
- One baseline policy is the floor. A business unit may add stricter rules; loosening needs a recorded, time limited exception.
- Deduplicate findings on component, version, vulnerability and repository, and rank them with one model. Platform severity labels are inputs, not the answer.
- Onboard in waves: pilot, production, long tail; report only first, blocking later.
- Report four numbers per business unit: coverage, open known exploited vulnerabilities in production, age of the oldest critical, overdue exceptions.
- Branch protection, platform permissions and CI runners stay platform specific. The program sets the standard; it does not replace them.
- Safeguard capabilities covered, with labels: SBOM generation and analysis (GA); SCA and vulnerability management with EPSS and KEV (GA); reachability analysis and prioritisation (GA); policies, gates and guardrails (GA); asset discovery and enforcement (GA); SSO with group mapping (GA); bulk export (GA); CLI (GA); autonomous remediation and fix pull requests (GA, ships switched off with every category set to Manual); desktop app. Source control integrations: GitHub (GA), GitLab (GA), Bitbucket Cloud (GA, with a current docs notice on private connections), generic Git (GA, read only), Azure DevOps (GA, switched on per workspace).
The problem: three platforms, three programs
A company buys two smaller ones. One built everything on a cloud hosted Git platform, one ran a self-managed GitLab server, and the acquirer has a large Bitbucket Cloud workspace plus a few teams on Azure Repos. Each platform has some built-in dependency alerting, and each team trusted its own. Then the CISO asks: "How many critical, exploited vulnerabilities do we have in production, by business unit?"
What breaks when each platform's native alerting is the program
Duplicate findings with different names. The same vulnerable library version sits in forty repositories across three hosts. One platform raises an alert per manifest, another groups per repository, a third uses a different advisory identifier because it draws on a different database. Added up, the total looks far larger than the real exposure, and nobody can say which alerts are the same problem.
Inconsistent severity. Platforms take severity from different sources and use different words. A finding that is "high" in one place is "moderate" in another. If your service level targets depend on severity, two teams with the same library get two deadlines.
Exceptions in three places. One developer dismisses an alert as "not used". Another team marks the same advisory "risk accepted" in a different screen. On the third platform nobody can dismiss anything without an admin role, so the alert is ignored. When an auditor asks for accepted risks and approvers, you have three partial exports, different fields and no expiry dates.
Coverage that depends on settings and tier. Built-in alerting is often switched on per repository or per organisation, and some features depend on the plan. After an acquisition, nobody knows which repositories had alerting on or which were never scanned.
Different ownership models. One platform has organisations and teams, another groups and subgroups, another workspaces and projects. None knows your business units, so routing a finding to its owner means joining platform data to your service catalogue by hand.
No single history. When a new exploited vulnerability is announced, you need to know within hours which repositories carry the affected version, which ship to production and who owns them. With three alert systems you run three searches in three query languages and reconcile them in a spreadsheet.
None of this is a criticism of the platforms. Their alerting helps the developers on that platform. A vulnerability program is a company level process with one inventory, one policy, one set of decisions and one record of evidence.
What the standards expect
The frameworks you are measured against assume one program, however many hosts you run.
NIST SP 800-218, SSDF v1.1. Practice PO.3, "Implement Supporting Toolchains", says automation should improve the accuracy and comprehensiveness of security practices and notes that toolchains may run organisation wide. Task PO.3.3 asks you to configure tools to generate artifacts showing the practices are followed, which is hard when each platform keeps a different record. PS.1 asks you to protect all forms of code from unauthorized access and tampering; you cannot protect repositories you have not listed. PW.4.4 asks you to verify that third party components meet your requirements, including regular checks for publicly known vulnerabilities. RV.1 and RV.2 ask you to identify vulnerabilities on an ongoing basis and remediate them according to risk, with RV.2.2 calling for a risk based decision on each one.
NIST SP 800-53 Rev. 5, CM-8 System Component Inventory. CM-8 asks for an inventory that accurately reflects the system, includes all components and does not include duplicate accounting of components. Its discussion allows a centralised inventory across systems. A program that counts the same library three times on three platforms fails the duplicate test before it starts.
CIS Critical Security Controls v8.1. Control 2 asks you to actively manage all software so unauthorized and unmanaged software is found. Control 7 asks for a plan to continuously assess and track vulnerabilities on all enterprise assets. Control 16 asks you to manage the security life cycle of in-house developed, hosted or acquired software.
OWASP SAMM v2. Policy and Compliance asks for security requirements that apply to all applications and, at its top level, for measuring each application's adherence. Defect Management at level 2 asks you to rate all security defects across the whole organisation consistently and set service levels per severity class. Three native alerting systems cannot give you that consistency.
NIST SP 800-40 Rev. 4 frames patching as preventive maintenance and recommends one enterprise strategy for identifying, prioritising, installing and verifying updates throughout the organisation.
CISA's KEV catalog and BOD 26-04. CISA issued BOD 26-04, "Prioritizing Security Updates Based on Risk", on 10 June 2026; BOD 22-01 is revoked. It requires federal civilian agencies to monitor KEV updates, set internal tracking and reporting, and remediate within timelines set by four factors: whether the asset is publicly exposed, whether the CVE is in KEV, whether exploitation can be automated, and whether an attacker gains partial or total control. BOD 22-01's fixed two-week KEV deadlines no longer apply. BOD 26-04 binds agencies, not suppliers unless their contract says so, but suppliers to those agencies get asked the same questions, and answering them needs one view across every platform. Our post on BOD 26-04's four factors covers the model in detail.
OpenSSF Scorecard. Its Branch-Protection check reads branch protection or repository rules settings, and its Vulnerabilities check looks for open, unfixed vulnerabilities using OSV. Some controls live in each platform's settings; others can be measured centrally.
How do you build one repository inventory and find the repos nobody registered?
Inventory comes first, because every later number has the inventory in its denominator. Scan before you know how many repositories exist and your coverage figure will look good for the wrong reason.
Step 1: Enumerate every repository from every platform
Pull the list from each platform's API with a read only token, not from a wiki page. These are the platforms' own documented interfaces; adjust the names.
# GitHub: every repository in an organisation, with archive status and last push
gh repo list my-org --limit 1000 --json nameWithOwner,isArchived,pushedAt,visibility
# GitLab: every project in a group, including subgroups
curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/groups/my-group/projects?include_subgroups=true&per_page=100"
# Bitbucket Cloud: every repository in a workspace
curl -u "$BB_USER:$BB_TOKEN" \
"https://api.bitbucket.org/2.0/repositories/my-workspace?pagelen=100"
# Azure DevOps: every Git repository in an organisation
curl -s -u ":$AZURE_DEVOPS_PAT" \
"https://dev.azure.com/my-org/_apis/git/repositories?api-version=7.1"
Page through the results, then repeat for every organisation, group and workspace. Acquisitions often bring more than one: a main organisation, a forgotten sandbox group, a personal workspace that holds a production service.
Step 2: Reconcile against what actually builds and ships
A repository list tells you what exists, not what matters. Join it to three other sources:
- CI systems. Every pipeline names the repository it builds. A pipeline building a repository not in your list means a missed host or a mirror.
- Registries and package feeds. Image labels and package metadata often carry the source repository URL. An image in production whose source is not in your list is the most important gap you will find.
- Deploy manifests and the service catalogue. They tell you which repositories run in production and who is on call.
Repositories that build or ship but are not in your list are the ones nobody registered: usually a self-managed server that came with an acquisition, a mirror on another platform, or a Git server behind a VPN.
Step 3: Keep one record per repository
| Field | Why it matters |
|---|---|
| Canonical URL and host | Separates the same name on two platforms; spots mirrors |
| Business unit and team | Routes findings and rolls numbers up |
| Owner (a person and a team alias) | Somebody must answer for every exception |
| Production status | Separates the repositories that ship from the rest |
| Data classification | Lets policy treat regulated data differently |
| Default and release branches | Tells the scanner which branch is what ships |
| Last scan date | Turns the inventory into a coverage number |
| Archived or retired, with reason | Keeps dead code out of the denominator |
Seed owners from CODEOWNERS files, platform teams or the service catalogue, then confirm with the teams. A repository with no owner is a finding in its own right. Where the same code is mirrored on two hosts during a migration, pick one canonical home, scan that, and record the mirror as a pointer so findings are not counted twice.
How should organisations, business units and teams map to scanning scopes and roles?
Do not copy any platform's grouping into the program. Map your company once, then attach every platform's repositories to that map.
| Your level | What it holds | What it controls |
|---|---|---|
| Company | Everything | Baseline policy, global settings, single sign on, who can change policy |
| Business unit | One unit's products and teams, including an acquired company not yet merged | Unit policy additions, unit reporting, unit administrators |
| Team or product | The repositories one team owns, on any host | Routing of findings, exception requests, triage |
| Repository and version | One codebase at one branch or tag | What is scanned and what a gate decides |
A team's repositories can live on two platforms and still roll up to one team. When the acquired company's repositories move to your main platform, only the host field changes.
Four roles cover most programs: company administrators (connect platforms, change the baseline), business unit managers (manage their unit, add stricter rules, approve exceptions within limits), users (developers who act on findings and request exceptions) and viewers (leadership and auditors). Assign them through identity provider groups so access follows people when they move teams. Keep these program roles separate from platform permissions: who can see findings and approve exceptions is a different question from who can push code or change branch protection.
How do you apply one policy everywhere while letting a business unit tighten it?
A single policy is the core of the program, and where most programs stall, because every unit has a reason it is different. The answer is a floor with room above it.
The baseline: a short, strict floor
The baseline applies to every repository on every platform. Keep it short enough that nobody can call it unreasonable:
- No known exploited vulnerability (listed in CISA's KEV catalog) in a production repository past a fixed number of days from listing.
- No critical vulnerability with a fixed version available, in a production repository, past a fixed number of days.
- No dependency under a licence your legal team has prohibited.
- Every production repository scanned within the last seven days.
Each rule has an action: block the release, warn, or notify the owner. New rules start as warn or notify for a few weeks so you can see what they would have blocked, then move to block.
Unit additions: stricter, never looser
A payments unit under PCI DSS might block any high severity vulnerability in services that handle card data. A newly acquired unit might start with notify only for everything except KEV, and move to the baseline on a fixed date. No unit may switch off or loosen a baseline rule; a real case where the rule is wrong is an exception.
One exception register for every platform
Every exception records the policy and finding, the business justification, any compensating control, the requester, the approver and an expiry date. Keep the register above the platforms. Dismissals in a platform's alert screen can stay as a developer convenience, but they do not count until they are in the register. At expiry the finding comes back. That register is the risk decision SSDF RV.2.2 asks for, written down.
One findings model: deduplicate and rank once
What one finding means
A useful key is component (as a package URL), version, vulnerability identifier, repository, and branch or version. Two alerts with the same key are one finding, whichever platform raised them. Link different identifiers for the same flaw (a CVE, a platform advisory ID, an OSV ID) as aliases of one vulnerability. The same component in forty repositories is forty findings with one fix: report "forty affected repositories" for routing and "one vulnerable component" for leadership.
One ranking, not three severity labels
Do not translate platform severity labels into each other. Rank every finding with the same inputs:
- Known exploitation: is it in CISA's KEV catalog?
- Exploit probability: its EPSS score from FIRST, free and updated daily.
- Reachability: does the application call the vulnerable code? Treat "unknown" as reachable.
- Environment: production, and does it handle regulated data?
- Fix availability: is there a fixed version, and how far away is it?
CVSS stays as a tie breaker. With one ranking, two teams with the same library on different platforms get the same deadline, which is the consistency SAMM's Defect Management asks for.
Old findings history
Native alert history does not move by itself. Export each platform's dismissals once and use them for one thing: re-reviewing the ones that should become formal exceptions, with a justification and expiry. Do not import old alert counts as a trend baseline; they came from a different engine.
How do you onboard hundreds of repos in waves without flooding teams?
Connecting everything on day one produces one enormous number and a lot of angry messages. Waves let you tune the program on a small group first.
| Wave | Scope | Mode | Exit criteria |
|---|---|---|---|
| 0: pilot | Five to ten repositories from two teams, on at least two platforms | Report only, no notifications | Scans succeed on every platform; findings match a manual spot check |
| 1: crown jewels | Production repositories with customer or regulated data | Report only, owner notifications on KEV only | Every repository has an owner; KEV rule in warn |
| 2: all production | Remaining production repositories, all platforms | Baseline in warn; KEV rule moves to block | Exception process used in every unit; no unresolved scan failures |
| 3: long tail | Internal tools, libraries, prototypes | Report only, weekly digest | Coverage above target; archive candidates recorded |
| 4: acquired estates | Each new acquisition as its own unit | Notify only for a fixed period, then baseline | Merged into the unit model; old dismissals re-reviewed |
Size each wave by your team's capacity to answer questions, not by scanner throughput. A few rules keep waves quiet:
- Report only first. For two weeks only the security team sees new findings, so scanner configuration problems are fixed before developers notice.
- Digests, not alerts. Only KEV listed findings in production page anyone.
- Fix shared components first. If one base image or internal library causes a third of the findings, fix it centrally before the wave goes live.
- Archive before you scan. Repositories untouched for two years and unclaimed go on an archive list.
- Announce, then connect. Tell each team the date, what they will see and how to request an exception.
How do you report one number per business unit to leadership?
Leadership wants one number. Give them the same small set for every unit.
- Coverage: the share of inventoried repositories scanned in the last seven days, and separately of production repositories. Coverage keeps the other numbers honest.
- Open known exploited vulnerabilities in production: KEV listed findings in production repositories without an active exception. The target is zero.
- Age of the oldest critical: days since the oldest open critical or KEV finding in production appeared. One old finding says more about process than a total.
- Overdue exceptions: exceptions past expiry that were neither renewed nor closed. A rising number means exceptions are being used as a dismiss button.
A worked example (illustrative, not data). Unit A has 180 repositories, 96% scanned, 2 open KEV findings in production, oldest critical at 21 days. Unit B, from an acquisition and spread across a self-managed server and a cloud workspace, has 240 repositories, 61% scanned and 0 open KEV findings. Unit C has 75 repositories, 100% scanned, 0 KEV findings, oldest critical at 9 days. On a vulnerability count, Unit B looks best. Coverage shows four in ten of its repositories are not scanned, so its zero means "unknown". The action is to finish Unit B's onboarding before anyone celebrates.
Avoid total vulnerability counts as a target. They rise every time you connect more repositories and punish the teams you just onboarded.
What stays platform specific?
| Control | Where it lives | What the central program does |
|---|---|---|
| Branch protection and rules (required reviews, required checks, no force push) | Each platform's settings | Defines the standard; checks it through each platform's API or OpenSSF Scorecard |
| Repository permissions and team membership | Each platform, ideally driven by your identity provider | Reviews access; keeps program roles separate |
| CI runners and pipeline definitions | Each platform's CI or a separate CI system | Supplies one scan step per CI system in shared templates |
| Required status check that enforces the gate | Each platform's branch protection | Names the check that must pass; the gate decides pass or fail |
| Integration tokens and service accounts | Each platform | Sets expiry and least privilege; tracks rotation |
| Webhooks and event delivery | Each platform | Decides whether to scan on push or on a schedule |
| Native alerting | Each platform | Allowed as a developer aid; not the system of record |
The required status check is the bridge. The gate decides centrally, but the platform blocks the merge, so each platform's branch protection must require the gate's check by name on the branches that ship.
How Safeguard does this job
Here is how Safeguard runs the same program, using only flows its documentation describes. SBOM generation and analysis (GA) and SCA with vulnerability management, including EPSS and KEV enrichment (GA), build the component inventory and findings. Reachability analysis and prioritisation (GA) ranks them. Policies, gates and guardrails (GA) apply one policy across the organisation. Asset discovery and enforcement (GA) looks for what is not yet governed. SSO (GA) and roles carry ownership. Safeguard describes this as one platform, one findings model and one policy engine.
Step 1: Set up the hierarchy before connecting anything
Safeguard organises data as Tenant › Organization › Project › Version. The docs describe organizations as logical groupings for business units, teams, project portfolios and access boundaries, and projects as the scanning units and the policy application scope. Products group projects so you see combined risk per release train or business unit.
- Go to Settings › Organizations.
- Click New Organization.
- Enter a name, a description and a primary contact email.
- Click Create.
Each organization has its own settings, including a default policy, notification settings, integration defaults and data retention. The per organization default policy is where a unit's additions start.
Roles are Tenant Admin (all organizations and settings), Manager (specific organizations, users and policies; per the docs' matrix, managing organizations and inviting users only within assigned organizations), User (assigned projects) and Viewer (read only). Teams can be given organization access, project access, notification preferences and policy ownership. With SSO, users are created on first login and group mappings under Settings › SSO › Group Mappings assign roles; the docs' example maps a security team group to Manager across all organizations, developers to User in Engineering, and auditors to Viewer.
The page also lists /v1 REST calls for users and organizations under a banner saying those endpoints are not available yet, so use the app.
Step 2: Connect each source control platform
Each integration is a card under Integrations on the Project/Product tab. Each selected repository, at a branch or tag, becomes a project that Safeguard clones and scans for an SBOM and findings. Every source control page says the scanner makes a shallow clone into a temporary folder, deletes it when the scan ends and does not store source code; tokens are encrypted at rest with a per workspace key.
| Platform | Label | What the docs say today |
|---|---|---|
| GitHub | GA | GitHub.com, Enterprise Cloud and Enterprise Server. Fine grained personal access token recommended (Metadata and Contents read only, selected repositories). No GitHub App or OAuth sign in yet. Enterprise Server must be reachable from the internet. No webhooks |
| GitLab | GA | GitLab.com and self-managed servers reachable from the internet. Least privilege: group access token, Reporter role, read_api and read_repository; add api and Developer for fix merge requests. No OAuth sign in. No webhooks |
| Bitbucket | GA for Bitbucket Cloud | Atlassian API token with Bitbucket scopes; repositories picked one workspace at a time. Data Center not supported yet. A current docs notice says private connections need a Safeguard update because Bitbucket Cloud retired two endpoints used to verify credentials; public repositories are not affected. No webhooks |
| Generic Git | GA | Any repository reachable over HTTPS from the internet, added by URL. Read only: no repository listing, fix pull requests or statuses. No SSH URLs. Hosts that check the username can pass the check and then fail the clone |
| Azure DevOps | GA | Switched on per workspace; ask Safeguard if the card is missing. Azure DevOps Services only, not Azure DevOps Server. Organization scoped token with Code (Read) and Project and Team (Read). Optional service hooks rescan on push and start a pull request review |
What matters most in a multi platform estate:
- Least privilege everywhere. For scanning Safeguard only reads. Write scopes are needed only for fix pull requests or merge requests, comments and the quality gate status. Start read only, with tokens owned by service accounts rather than people.
- Token expiry. The docs suggest expiries such as 90 days and say scans fail until a new token is pasted in. Keep every integration token's expiry in one calendar and rotate through the connection's Update menu under Project Configurations. The Azure DevOps page notes global personal access tokens stop working on 1 December 2026.
- Unreachable servers. Safeguard does not send a token to private or internal addresses. For a server behind a VPN, scan inside your network from CI with the local option (Step 4), which scans on the runner and uploads only results.
- Connecting. Choose Public or Private, name the connection, say where the platform runs, paste the token and check it. Select repositories and a branch or tag for each, then Connect with Fast, Deep or Progressive scan (fast now, full depth after). Progressive suits a large wave.
Step 3: Set the rescan cadence
GitHub, GitLab and Bitbucket have no webhooks to set up. Each repository is scanned when connected; to rescan new commits, the docs say to set a schedule under Integrations › Scheduled or choose Rescan from the connection's menu. Azure DevOps (early access) adds optional service hooks for push and pull request events. So you run two clocks: the schedule keeps every repository fresh, including the long tail, and CI scans cover merges and releases. If coverage means "scanned in the last seven days", schedule at least weekly.
Step 4: Put one scan step in each CI system's shared template
Every CI page uses the same command, safeguard ci scan. Create a secret key under Settings › Developer with the scopes scans:trigger and scans:read, and store it as SAFEGUARD_API_KEY in each CI system. For GitLab CI/CD the docs offer an included template; take the remote URL from the GitLab CI/CD docs page:
include:
- remote: <template URL from the GitLab CI/CD docs page>
safeguard:
extends: .safeguard-scan
variables:
SAFEGUARD_FAIL_ON: critical
It defines a hidden .safeguard-scan job in the test stage. SAFEGUARD_BRANCH_PATTERN picks branches, an empty SAFEGUARD_FAIL_ON means no severity gate, and SAFEGUARD_LOCAL set to "true" scans on the runner and uploads only results with no integration needed: the route for a self-managed GitLab server Safeguard cannot reach.
For Bitbucket Pipelines the docs show a step on an Alpine image:
definitions:
steps:
- step: &safeguard-scan
name: Safeguard scan
image: alpine:3.20
script:
- apk add --no-cache bash curl ca-certificates
- curl -fsSL https://cli.safeguard.sh/install | SAFEGUARD_INSTALL_DIR=/usr/local/bin bash
- safeguard ci scan --wait --fail-on critical
pipelines:
branches:
main:
- step: *safeguard-scan
pull-requests:
'**':
- step: *safeguard-scan
The GitHub Actions and Azure Pipelines pages follow the same pattern; the Azure page notes that for Azure Repos the pr block is ignored and you add a Build validation branch policy instead. Across all of them: drop --fail-on critical for report only, add --local to scan on the runner, add --project-id for a specific project, and pin the CLI with SAFEGUARD_VERSION. Put the step in each CI system's shared template, not in each repository, so one change starts a wave.
Step 5: Write the baseline as policies, link them to gates
Policies evaluate SBOMs and generate findings; gates are the checkpoints that enforce them. The docs' policy builder:
- Go to Settings › Policies.
- Click Create Policy.
- Define conditions with the visual builder or YAML.
- Set severity and the action.
- Save and enable.
Conditions include vulnerability severity, CVSS, EPSS, licence, component age, maintenance and SLSA level; templates include No Critical Vulnerabilities, License Compliance and No Abandoned Packages. Gates are evaluated by the platform on the scans it runs for your connected repositories, so one policy covers repositories from every host without being copied.
Each policy has one action: Block (the gate fails), Warn (the gate passes with a warning naming the policy) or Notify (the gate passes and the workspace's channels are notified). Notify fires when a policy starts failing and again on new matches, not on every evaluation, which keeps waves quiet. An Error never counts as a pass.
Policy outcomes are switched on per workspace by Safeguard and are off by default; if the Gates and Policies tables have no Outcome column, ask your Safeguard contact. With outcomes on, CI can fail on the gate rather than on raw severity:
safeguard ci scan --wait --fail-on-gate all
It exits 0 on Passed or Warning and non zero on Failed, Error or Not evaluated. That is the check each platform's branch protection should require. A unit's additions go in its organization as extra policies linked to its gates; the baseline stays linked everywhere.
Step 6: Run exceptions through one workflow
The docs describe one exception flow for every repository, whatever its host:
- The developer clicks Request Exception.
- They select the policy and the finding.
- They give a business justification.
- They set an expiration date.
- They submit; approvers are notified, decide, and an audit trail is recorded.
Approval runs through this workflow; the gate actions themselves are Block, Warn and Notify. Compliance reporting shows status by policy, exception history and violation trends: the single register, with expiry built in.
Step 7: Use asset discovery to find what is not governed
The asset discovery docs describe cataloguing repositories from Git providers along with images, packages and SBOMs, binding each to an owner and business context, and flagging shadow assets, such as a new repository in your organisation that is not connected, with an UNGOVERNED status. Ownership can be inferred from CODEOWNERS or assigned by hand, and the dashboard tracks ownership coverage over time. Discovery only sees what your tokens let it see. The page's /v1 calls carry the "not available yet" banner and there is no CLI command for assets yet, so work in the app.
Step 8: Roll up reporting and turn on fixes deliberately
Group each unit's projects into Products for combined risk per unit; the dashboard shows projects, components, vulnerabilities, critical counts and MTTR trends, and bulk export (GA) sends the four numbers wherever leadership reads. Autonomous remediation (GA) can open fix pull requests on GitHub, Bitbucket and Azure DevOps and fix merge requests on GitLab when the token has the write scope each page lists. It ships switched off with every category set to Manual. Turn it on one platform and one unit at a time, after that platform's branch protection requires review.
Requirement versus what Safeguard does versus what you still own
| Requirement | What Safeguard does | What you still own |
|---|---|---|
| One inventory (CM-8, CIS Control 2) | A project per connected repository across supported hosts; asset discovery flags ungoverned repositories it can see (GA) | Token reach; unsupported hosts; reconciling with CI and deploy data |
| Ongoing identification (SSDF RV.1, CIS Control 7) | Scans on connect, on schedule and from CI; SCA with EPSS and KEV (GA) | Cadence that meets your coverage target; CI templates on every platform |
| Consistent rating (SAMM Defect Management) | One findings model and ranking for every repository (GA) | Service levels per rank; defining "production" |
| One policy for all applications (SAMM Policy and Compliance) | Org wide policies and gates with Block, Warn, Notify (GA); per organization default policy | Baseline content; unit additions; moving rules to block |
| Risk decisions recorded (SSDF RV.2.2) | Exception workflow with justification, expiry, approval and audit trail | Approver discipline; review at expiry |
| Ownership and access | Tenant, Organization, Project, Version; roles; SSO group mapping (GA) | Identity provider groups; platform permissions |
| Merge blocked on failure | --fail-on-gate in CI; quality gate status with write scope | Branch protection requiring the check on every platform |
What Safeguard does not do
- It does not cover every host. Integrations are GitHub, GitLab, Bitbucket Cloud and generic Git (GA), and Azure DevOps (GA, per workspace). Bitbucket Data Center and Azure DevOps Server are not supported yet, and self-hosted servers must be reachable from the internet. Otherwise, scan in your own CI with the local option.
- It does not manage platform permissions or branch protection. Who can push, approve and which checks are required stay in each platform.
- Discovery depends on the access you grant. A token scoped to selected repositories, or a workspace you never connected, stays invisible.
- Findings history from old tools does not migrate automatically. Native dismissals must be re-reviewed and entered as exceptions.
- Policy outcomes are off by default. Failing CI on a gate needs Safeguard to turn them on for your workspace; until then use
--fail-onwith a severity. - No event driven rescans on GitHub, GitLab or Bitbucket. Those rescan on a schedule or by hand; CI covers merges and releases.
- No public
/v1API for organizations, users or assets yet. Automate through the CLI and CI, or use the app. - This is a dependency vulnerability program. SAST is generally available and not part of
--fail-onyet, and ticketing integrations are generally available, so plan routing inside Safeguard and your own tools.
Common mistakes
Scanning before inventorying. Coverage looks excellent because the denominator is only what someone remembered to connect.
Copying each platform's group structure. You end up with three hierarchies again.
Letting units loosen the baseline. Once one unit has a weaker floor, every unit asks for one.
Personal tokens for integrations. When the person leaves, a platform's scans silently stop. Use service accounts and track expiry.
Native dismissals as the exception record. They have no expiry and no approver.
Blocking an acquired estate on day one. Start it on notify, with a known date for the baseline.
Forgetting the required status check. The gate fails, branch protection does not require the check, and the merge goes through.
Counting mirrors twice. Pick a canonical home for each repository.
FAQ
How do I manage vulnerabilities across GitHub, GitLab and Bitbucket in one place?
Put one scanner and one findings model above the platforms: one inventory with owners, one engine, one ranking, and one policy enforced through a CI step on each platform. Native alerts stay as a developer aid.
Should I turn off each platform's built-in dependency alerts?
Not necessarily. Developers may like them in pull requests. Just make sure exceptions, service levels and reporting come from the central program.
How do I find repositories nobody registered?
List repositories from every platform's API for every organisation, group and workspace, then join that list to CI pipelines, image labels and deploy manifests. Anything that builds or ships but is not listed is unregistered.
How do I normalise severity across different platforms?
Do not map labels onto each other. Rank every finding on KEV listing, EPSS, reachability, environment and fix availability, with CVSS as a tie breaker.
Can one security policy apply to repositories on different platforms?
Yes, if the policy lives above the platforms and a CI step on each one asks for the gate decision. Each platform then requires that check in branch protection.
How should acquired companies fit into the program?
As their own business unit, with the baseline policy, a unit manager, and a fixed date to move from notify only to the full baseline.
How many repositories should be in each onboarding wave?
As many as your team can answer questions about in a week. Start with five to ten on at least two platforms.
What should I report to leadership?
Per business unit: coverage, open known exploited vulnerabilities in production, age of the oldest critical, and overdue exceptions.
Does Safeguard support Azure DevOps and Bitbucket Data Center?
Azure DevOps Services is generally available and switched on per workspace. Bitbucket Data Center and Azure DevOps Server are not supported yet, per Safeguard's docs.
Does Safeguard store my source code when it scans?
Per each source control integration's docs, no. The scanner makes a shallow clone into a temporary folder, deletes it when the scan ends, and stores the SBOM and findings.
When a finding needs a fix, not another dashboard
One program is only worth building if findings close. On every platform the fix is the same job, moving a dependency to a safe version or finding one when upstream has none, which is what the next section covers.
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 first demo is a real CLI session. After installing, safeguard opens the interactive terminal and the user asks it to fix the lodash CVE in the repository. 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 approval, prints a summary and pushes nothing, then shows /permissions, /model and /scan .. The same CLI runs in every CI template above, so a developer on any platform can reproduce a gate's finding and fix it locally.
Click through it at your own pace, or open it full screen.
The second demo is a desktop app session. The CLI session shows in the conversation list, you ask for work on your computer, pick the folder, then Approve or Deny each command and file edit, and it ends with an upgrade done and tests passing. For a platform lead fixing a shared component that causes findings on several hosts, that is one reviewed change instead of three alert workflows.
Click through it at your own pace, or open it full screen.
To try the CLI or the desktop app, start at safeguard.sh/download, and read the setup guides at docs.safeguard.sh.
Related reading
- Onboard hundreds of repos to vulnerability scanning in waves
- Move from per-repository alerts to an org-wide vulnerability view
- Keep security settings consistent across hundreds of repositories
- Delegated admin and scoped access in SCA for business units
- Run AppSec with one security engineer per 100 developers
- Prove every production release passed a security gate
Quick check
An acquired unit reports zero open critical vulnerabilities, but only 55% of its repositories are scanned. What do you report?
Report coverage first. Zero findings on a half scanned estate means "unknown", not "clean". Finish the unit's onboarding wave, then read the vulnerability numbers.
A business unit wants to switch off the baseline KEV rule for one legacy service. How should the program handle it?
As an exception, not a policy change. Record the finding, the justification, any compensating control, the approver and an expiry date in the one register. At expiry the finding comes back.
Sources
- NIST SP 800-218, Secure Software Development Framework (SSDF) Version 1.1
- NIST SP 800-218 full text (PDF)
- NIST SP 800-53 Rev. 5, Security and Privacy Controls
- NIST SP 800-53 Rev. 5 full text (PDF)
- NIST SP 800-40 Rev. 4, Guide to Enterprise Patch Management Planning
- CIS Critical Security Controls v8.1
- CIS Control 2: Inventory and Control of Software Assets
- CIS Control 7: Continuous Vulnerability Management
- CIS Control 16: Application Software Security
- OWASP SAMM: The Model
- OWASP SAMM: Policy and Compliance
- OWASP SAMM: Defect Management
- OWASP SAMM: Strategy and Metrics
- OpenSSF Scorecard
- OpenSSF Scorecard checks documentation
- CISA: Known Exploited Vulnerabilities Catalog
- CISA: BOD 26-04, Prioritizing Security Updates Based on Risk
- CISA: BOD 22-01 (revoked)
- FIRST: Exploit Prediction Scoring System (EPSS)
- Safeguard docs: Integrations
- Safeguard docs: GitHub integration
- Safeguard docs: GitLab integration
- Safeguard docs: Bitbucket integration
- Safeguard docs: Azure DevOps integration
- Safeguard docs: Git (generic Git URL) integration
- Safeguard docs: Organization and User Management
- Safeguard docs: Asset Discovery
- Safeguard docs: Policies and Gates
- Safeguard docs: Policy outcomes and actions
- Safeguard docs: GitHub Actions
- Safeguard docs: GitLab CI/CD
- Safeguard docs: Bitbucket Pipelines
- Safeguard docs: Azure Pipelines
Last reviewed: 24 October 2026. Product capabilities change; check docs.safeguard.sh for the current state.