Inspiration
In 2026, the registry itself became the attack surface.
Mini Shai-Hulud poisoned 373 versions across 169 packages in a single day through one hijacked CI workflow. A single actor published 14 typosquats in four hours to steal cloud and CI secrets. Red Hat's namespace got hijacked, 36 packages hid malware in postinstall binaries, fake Paysafe and Skrill SDKs hunted credentials, one stolen login turned Keyv — with 127 million weekly downloads — into a self-spreading worm, and a Go worm jumped from npm to PyPI.
Every one of these attacks walked in through a dependency change on an otherwise boring merge request.
We built Chain-Guard so that no dependency ever merges without a supply-chain review.

What It Does
Chain-Guard is a supervised-autonomy supply-chain monitor for GitLab merge requests.
A deterministic Python engine diffs dependency manifests, checks every new version against OSV, flags typosquats using edit distance, and identifies floating version ranges and missing lockfiles.
The scanner is fully offline-capable and fails open: when the network is down, the result is UNKNOWN, never a false BLOCK.
Then two GitLab Duo agents take over:
- Reviewer agent: Posts an
ALLOW,PIN, orBLOCKverdict as a merge request comment, including a machine-readable<!-- chain-guard:verdict=... -->trailer. - Pin-applier agent: Only after a human approves at the
pin_gate, commits exact pinned versions.
On a BLOCK verdict, nothing is pushed. Ever.
Deterministic CI remains advisory-green; the Duo flow is what enforces the verdict. A passive monitor flow also reuses the same engine for nightly rescans.

How We Built It
The scanner is a standard-library-only Python engine organized under src/chainguard/, with modules for dependency diffing, OSV lookups, typosquat detection, pinning, reporting, and CLI operations. This keeps the slim runner image from breaking because of dependency installation issues.
The system integrates with:
- A nine-stage CI pipeline for automated checks.
- A Cloud Run status API for exposing pipeline status.
- Two custom GitLab Duo agents for review and pinning.
- Two Flow Registry v1 flows, configured with the
ambientenvironment. - Four trigger conditions: Merge request creation or updates, comment commands, and nightly scheduling.
The flows are trigger-agnostic and driven by context:goal.
For the demo, we used a deliberately vulnerable application. Merge request !2 introduces axois, a typosquat of axios.
The recorded session demonstrates the full workflow:
- Detect the malicious dependency.
- Generate a
BLOCKreport. - Pause for human approval.
- Provide guidance through the pin-applier flow.
- Finish the session without pushing a commit on
BLOCK.
Recorded session: Chain-Guard Agent Session 10116629
The demo video introduction was rendered with HyperFrames using a specification-reviewed composition: 36 seconds across eight slides.
Demo outcome: A BLOCK verdict, a flagged typosquat, proposed pins, and absolutely nothing pushed.

Challenges We Ran Into
1. The Duo Ambient Flow Exited with Code 127
The flow failed immediately because the minimal image lacked git, curl, and a configured Git identity.
We fixed this by pinning a full python:3.12 image and configuring the Git identity in the setup_script.
2. Playwright Couldn't Attach to Firefox
For the demo recording, Playwright couldn't attach to the running Firefox instance.
Instead of fighting the browser connection, we switched to native browser control using cua-driver under Xorg and captured the screen with FFmpeg's x11grab.
3. A Runner Flake Turned the Pipeline Red
A runner issue caused the pipeline to fail midway through the demo, although it passed on retry.
The SAST bridge job also failed closed when no downstream job was available. We made it advisory, aligning it with our core philosophy: scanners provide information, while the flows enforce the verdict.
4. Human Approval and Trigger Semantics Shaped the Architecture
The Flow Registry's resume contract requires a human_approval boolean. Combined with the rule that flows only fire on human actions, this shaped our entire autonomy ladder.
These constraints helped establish a clear boundary between automated detection, agent recommendations, and human-authorized actions.
Accomplishments That We're Proud Of
We demonstrated end-to-end supervised autonomy on camera.
A poisoned merge request triggers the review flow. The reviewer identifies a real typosquat and cites OSV advisories in a BLOCK report. The flow pauses at the approval gate, a human approves, and the applier provides guidance without pushing a single commit on BLOCK.
Beyond the live demonstration, we delivered:
- A deterministic scanner: All 9 tests passing.
- A complete public repository: Including full CI pipeline history.
- A working supervised-autonomy workflow: With explicit human approval before pinning actions.
- A rendered HyperFrames introduction: Built from a specification-reviewed composition.
- A focused demo: Three minutes or less.
- A second live test case: A merge request introducing
lodahs, staged so judges can watch the detection workflow happen again.
The result is more than a dependency scanner. It's a workflow that connects deterministic security checks, AI-assisted review, and human-controlled remediation.
What We Learned
Scanners should inform, not enforce.
Keeping the engine fail-open and advisory while placing BLOCK authority in the Duo flow, behind a human approval gate, made the system safer and easier to demonstrate.
We also learned that real-world attack data — including Shai-Hulud, Keyv, and supply-chain attack scenarios such as supplychain.local — provides a stronger foundation for both system design and storytelling than synthetic fixtures alone.
Finally, the unglamorous details are what turn an agent demo into infrastructure:
- Configuring Git identity in setup scripts.
- Documenting and wiring trigger conditions correctly.
- Using machine-readable verdict trailers.
- Defining clear human-approval and flow-resumption contracts.
- Separating detection from enforcement.
Reliable security automation depends as much on these operational details as it does on the scanner itself.
What's Next for Chain-Guard?
We're planning to expand Chain-Guard in five directions:
- Complete trigger automation: Wire triggers #2–4 and activate the nightly passive monitor for hands-off operation.
- SBOM and lockfile enforcement: Add CycloneDX SBOM export and stronger lockfile-diff enforcement.
- Broader ecosystem coverage: Extend the engine to Go modules and container base images.
- Safer automated remediation: Let the pin-applier propose and push fix commits for non-
BLOCKverdicts, subject to the appropriate authorization controls. - Reusable installation: Publish the trigger pack so any GitLab project can install supply-chain review in minutes.
Our goal is simple: make supply-chain review a standard part of every merge request, without sacrificing developer velocity or human control.
Built With
- claude
- duo
- gitlab
Log in or sign up for Devpost to join the conversation.