Inspiration

Coding agents now add dependencies on their own, sometimes on an AI assistant's advice, and npm attackers already aim at them: the nx malware ran its victims' AI CLIs, and the keyv worm planted agent hooks. Advisory feeds arrive late. The first OSV entry for the March 2026 axios hijack appeared 2.9 hours after publication, and until an advisory exists npm audit has nothing to report.

Dep Bouncer (MIT, built Oct 16-18 for an MCP hackathon) checks an npm release against the package's own history before an agent installs it. Its own release process was manual: tests in GitHub Actions, zip uploads, deploys that failed when two pushes landed close together, smoke tests nobody acted on. Path B asked what a real project gains on GitLab's full lifecycle. Our answer: everything after the code, run by agents that are held to the same dependency rules as the pipeline.

What it does

One human action starts the feature path: create an issue and assign it to the Autopilot.

  1. Plan. The planner posts acceptance criteria, files, dependencies and risk.
  2. Create. The builder implements it with tests. Before adding a package it asks Dep Bouncer and pins a version only when Dep Bouncer allows it and OSV reports no advisory; the merge request records each decision.
  3. Verify and Secure. The pipeline runs the dependency gate on every changed lockfile entry (transitive and workspace-installed, up to 60 package versions per MR), typecheck, 300+ tests, a replay of five real hijacks, SAST, secret detection and dependency scanning.
  4. Govern. A merge-policy job decides from the pipeline's own evidence: a live ALLOW, every job passed, no new High/Critical finding in a dependency the MR changes, no control files changed.
  5. Land. The shipper waits for the pipeline, fixes what fails, and lands a merge commit whose tree equals the tested commit. GitLab records the merge by the agent's service account.
  6. Package and Release. The image goes to staging by digest, is smoke-tested until it serves the expected build, is promoted to production and smoke-tested again; a failed production smoke rolls back. A GitLab release follows.
  7. Receipt. The agent posts a receipt on the issue: timeline, nine stages with evidence links, the build production serves, and the count of human actions.
  8. Monitor and respond. Every 30 minutes a scheduled pipeline checks production and whether it serves the default branch's build. A failure starts the Production Responder: it opens an incident, explains the cause, restores production through the normal pipeline and verifies it.
  9. Attack path. When a person's merge request pulls in a hijacked release, the gate blocks it. The Dependency Guardian explains the evidence, quarantines the MR, opens a confidential security issue and a replacement MR with a clean version, and ships it through the same path.

Who it's for

Teams that let coding agents change their dependencies. An agent that runs npm install mid-task is exactly where a hijacked release gets in, hours before any advisory. Dep Bouncer puts the check at that moment, in the agent and in CI, and the GitLab flows make the safe path the automatic one.

What's new

  • The agents are held to the dependency rules too. The builder vets every package before it adds it. Asked to switch to chalk-next, an AI-recommended "fork" that npm had removed as malware, the Autopilot refused and explained why (issue #11). OSV has no entry for it.
  • A hijacked dependency is not just blocked. An agent replaces it with a clean version and takes that to production with no human (4 of 4 replays).
  • It works before an advisory exists. The detector judges a release by the package's own history: publisher, provenance, install scripts, new dependencies and code changes. One of the fixes the agents shipped closes a real attacker technique: a release that only adds an install hook to run code that was already in the package, unchanged (issue #14).

Results

Every figure links to a public receipt, merge request or pipeline on the judge page and in docs/JUDGING.md.

  • 11 changes taken to production by the agents: 7 from issues (a YAML policy feature, a semver refactor, four detector bug fixes, a CLI improvement) and 4 replacements of hijacked dependencies. The six issue runs with receipts took 16.7-28.1 minutes with 0 counted human actions after the issue was created. 8 of the 11 changes have public receipts.
  • Attack day: 4 replays (labelled, benign reconstructions) of real hijacks: axios 1.14.1, keyv 6.0.0, chalk 5.6.1, @ctrl/tinycolor 4.1.1. Each was blocked within about a minute, quarantined and replaced by a clean version in production.
  • Drift drill: we put an old build on production by hand. The Production Responder restored and verified it in 13.3 minutes with 0 human actions, measured from the monitor run that started its session (the platform failed an earlier session 30 minutes before).
  • All nine lifecycle stages have a recorded run, each linked in docs/JUDGING.md.
  • Detector benchmark: MR and main (push) pipelines replay 5 reconstructed hijacks and require 5/5 BLOCK; a one-off sample of 200 popular releases (Oct 17) gave 199 ALLOW, 1 REVIEW, 0 BLOCK.

How we built it

  • Three custom GitLab Duo flows (flow registry v1, ambient): Autopilot (planner, builder, shipper), Dependency Guardian (guardian, shipper) and Production Responder. Triggers: Assign, Mention, and Pipeline failed (merge request pipelines for the Guardian, scheduled pipelines for the Responder).
  • Agent configuration (.gitlab/duo/agent-config.yml): the agents use a trusted Dep Bouncer built from the default branch; workspace dependencies are installed only when manifests, lockfiles and npm configuration match the default branch, with tokens stripped and install scripts off; exact network allowlist.
  • Deterministic tools the agents call: scripts/check.mjs, ci/autopilot.mjs (wait, land, rebase, wait for production, receipt) and ci/responder.mjs (diagnose, open, restore, receipt). No language model writes a number in a receipt.
  • CI/CD: parent/child pipelines, merge-policy job, environments, resource group, releases, schedules, SAST, secret detection, dependency scanning, container registry.
  • No GitLab or Render account token is stored in CI. Deploys use per-service Render deploy hooks (masked, hidden, protected, environment-scoped) that can only redeploy this project's images.
  • Evidence pages and the judge page are generated from the GitLab API.

Challenges we ran into

  • Developer role only: no project access token, no protected environments, no project settings. A flow's token cannot press Merge but can push to the default branch, so landing became a verified push of the approved tree, and deploys moved to per-service hooks.
  • Rehearsals found real bugs, each fixed and documented: the agents' setup would have installed a hijacked lockfile on the runner; a project .npmrc could route the agent's token; the policy refused a clean upgrade because the newest default-branch pipeline was a monitor run without a scan; a new advisory for an untouched dependency froze every merge.
  • Platform sessions sometimes fail: one Guardian session dropped (WebSocket 1013) and the Responder's first session failed before its first step; both completed on the next trigger.

What we learned

Deterministic tools for everything that can be checked, and agents only for judgment, made the runs repeatable: receipts, landing and restores never depend on what a model writes. Publishing every number with a link kept our own claims honest: when a figure could not be linked, it came out.

Honest limits

Landing is a verified push, not a protected merge; the agents share their token with the commands they run; the attacks are replays of removed malicious releases; the drift fault was injected by hand; production runs on Render's free tier, not Google Cloud. Details: README, Honest limits.

What's next

Publish the flows in the GitLab AI Catalog, add PyPI support, and integrate with GitLab's Dependency Firewall.

Built With

  • docker
  • gitlab
  • gitlab-ci
  • gitlab-container-registry
  • gitlab-dependency-scanning
  • gitlab-duo-agent-platform
  • gitlab-pages
  • gitlab-sast
  • gitlab-secret-detection
  • model-context-protocol
  • nitrostack
  • node.js
  • npm
  • osv
  • render
  • typescript
Share this project:

Updates

Submission history