In my last article, I walked through how we built an AI agent to fix vulnerabilities for a client, while keeping production approval with the application team.
Once you start automating changes, a second question comes up quickly. Do you know exactly what each change introduces?
Take a common fix, a base image update:
- FROM node:20.11-alpine
+ FROM node:20.18-alpine
One line. The scanner flagged a vulnerability, the agent bumped the image, and the tests passed. Easy to approve.
But that one line can change dozens of operating system packages underneath it. Some get upgraded. Some get added. Some disappear. None of that shows up in the pull request.
A one-line pull request is not a one-line change.
That's why I'd make SBOM comparison part of any automated remediation workflow. Not as a compliance file you generate once a year, but as part of how every change gets reviewed and approved. Here's how I'd build it in.
What the pull request doesn't show
A source diff shows what someone typed. It doesn't show what ended up in the artifact you deploy. Three things hide underneath a small change:
- Operating system packages. A new base image tag can bring a different version of nearly every package in the image.
- Transitive dependencies. Updating one library can pull in new libraries that it depends on, and those have their own dependencies.
- Lock files nobody reads. Package managers do record transitive changes. But a lock file diff runs hundreds of lines, and in practice, reviewers skip it.
To be clear, this isn't an AI problem. It's an old supply chain visibility problem. A few incidents show the different ways it bites:
- event-stream (2018): a malicious dependency, flatmap-stream, arrived through a routine update of a trusted npm package. Nobody chose it.
- Log4Shell (2021): the vulnerable library was often buried several layers deep, so many teams spent weeks just finding where it was.
- xz Utils (2024): a backdoor was planted inside a trusted, widely used compression library, the kind of OS package that rides along in a base image update.
AI doesn't create this problem. It speeds it up. An agent fixing vulnerabilities around the clock opens far more of these small pull requests than a human team would. Each one looks harmless. Without better visibility, review turns into a rubber stamp.
How I'd build it into the pipeline
An SBOM, a Software Bill of Materials, is an inventory of the components in a build: libraries, their dependencies, OS packages, versions, and licenses. The two common formats are CycloneDX and SPDX.
On its own, an SBOM is a snapshot. The value for remediation comes from comparing two of them. Here are the five steps I'd add, and the design choice behind each.
1. Generate it from the final image, by digest
Generate the SBOM from the container image you'll actually deploy, not from package.json or requirements.txt. Manifests miss the OS packages and anything the base image brings in, and those are often what Inspector flags.
Reference the image by its digest, not its tag. A tag like node:20.18-alpine can be moved to point at a different image later. A digest can't. If the SBOM describes a tag, you can't be sure it describes what you shipped.
trivy image --format cyclonedx --output sbom.cdx.json $IMAGE@$DIGEST
One caveat: an SBOM is only as complete as the tool that built it. Vendored code, static binaries, and less common package ecosystems can be missed. Treat it as a strong inventory, not a perfect one.
2. Attach it as a signed attestation
Sign the SBOM with cosign and attach it to the image digest.
cosign attest --predicate sbom.cdx.json --type cyclonedx $IMAGE@$DIGEST
Be precise about what this buys you. The signature makes tampering detectable and ties the SBOM to one specific image. It doesn't prove the SBOM is complete or accurate. That depends on step 1.
3. Compare it against the last approved release
Pull the SBOM from the release currently approved for production and compare. The CycloneDX CLI can diff component versions:
cyclonedx diff approved.cdx.json sbom.cdx.json --component-versions
You want three lists: components added, removed, and changed. License changes may need a small script on top, since not every diff tool reports them.
4. Gate with rules, not a blanket "no"
A new dependency isn't automatically bad. If every change fails the gate, people learn to override it. I'd sort the diff into three buckets:
- Block: a new component with a known exploited vulnerability, or a license your policy doesn't allow.
- Flag for human review: a brand-new dependency, a major version jump, or a component from an unfamiliar source.
- Allow: patch-level updates to components you already have.
And don't gate on severity alone. A "High" in a library that's never loaded matters less than a "Medium" on an internet-facing service. CISA's Known Exploited Vulnerabilities catalog and exploit likelihood scores like EPSS make the gate much smarter.
grype sbom:./sbom.cdx.json --fail-on high
A failed gate goes back to the agent with the evidence attached, the same way failed tests do. Attempts are capped, and anything unresolved escalates to a person.
5. Put the diff where the reviewer already looks
The agent posts the SBOM diff, with flagged items at the top, as a comment on its own pull request. The reviewer sees the real change without leaving the review. A reviewer who sees three new transitive dependencies and a license change will ask better questions than one who sees a single line.
If I had to reduce all of this to one rule for agent-made changes, it would be: no SBOM diff, no merge.

What an SBOM doesn't solve
SBOMs are useful, but they get oversold. Here's what they don't do.
- They tell you what's there, not whether to trust it. The xz Utils backdoor had no CVE when it shipped. A vulnerability scanner would have passed it. The SBOM diff would have shown the version change, which is exactly why new or changed components get flagged for human review instead of auto-approved.
- Signing isn't provenance. A signed SBOM proves who vouched for the inventory. Build provenance, such as SLSA attestations, records where and how the artifact was built. They're related controls, but they answer different questions. You want both.
- Present doesn't mean exploitable. An SBOM shows a vulnerable library is in the image. It doesn't show whether that code is ever loaded, or whether the service is reachable from the internet.
- Faster triage, not finished triage. When the next Log4Shell lands, searching stored SBOMs tells you in minutes which images contain the component. That's a huge head start over weeks of digging. But you still need to check runtime exposure and reachability before you know your real risk.
None of this replaces the human approval step from the last article. The SBOM diff just makes that approval informed.
The federal and regulated angle
There's a lot of loose talk about an "SBOM mandate." The actual picture is narrower, and worth getting right.
- Executive Order 14028 (2021) directed federal guidance on software supply chain security, including SBOMs. NTIA then published the minimum elements an SBOM should contain.
- OMB M-22-18, updated by M-23-16, requires software producers selling to agencies to attest to secure development practices, using CISA's attestation form. Agencies may also require an SBOM, based on how critical the software is. Attestation is required. An SBOM is often requested, but not universal.
- FDA Section 524B requires SBOMs in premarket submissions for medical devices that qualify as cyber devices. That's a device requirement, not a general healthcare or HIPAA rule.
If you're in one of these environments, the pipeline above does double duty. Every build already produces a signed SBOM tied to an exact image, and every change has a reviewed diff. When an agency asks for an SBOM, or an assessor asks how you control changes, the evidence already exists.
Where I'd start
If you're bringing AI agents into remediation or development, I'd start with three things:
- Generate SBOMs from the built artifact, by digest. Not from manifests. You need to see what you deploy, OS packages and transitive dependencies included.
- Compare every build to the last approved release. Sort the changes into block, flag, and allow, and use exploitability, not just severity, to decide.
- Put the results where review already happens. Nobody should have to generate or compare SBOMs by hand. The pipeline does it, and the pull request shows it.
None of this needs new budget. The core tools are open source, and most teams already run some of them. It's mostly a matter of wiring the right checks into the process you already have.
At Zephon, that's how we approach secure pipelines: use what you have, make the controls part of the workflow, and keep a person accountable for the decision. If you're working through this for your own environment, happy to compare notes.
AI will help us fix vulnerabilities faster. We still need to know what we're changing.
