Inspiration

Most security alerts die in a backlog. Small product teams and open-source maintainers get the same advisory emails as large companies, but there is no security engineer to triage them, no release manager to roll the fix out safely, and no compliance person to write down what happened. So known, already-fixed CVEs stay in production for weeks. We wanted the boring, careful remediation work to happen on its own, with guardrails strong enough that nobody has to be paged.

What it does

Zero-Day Medic is a hands-off remediation loop built on the GitLab Duo Agent Platform and GitLab CI/CD that covers all 9 DevSecOps stages:

  1. Monitor (watch): a scheduled pipeline checks every pinned dependency against OSV.dev (CVSS v3.1 scoring, GHSA/PYSEC de-duplication, minimal fixed version). Run live today against the demo service, it finds 4 advisories: a critical one in certifi and three in requests 2.31.0.
  2. Plan: one de-duplicated issue per package with the CVE table, severity labels, affected file and line, a reachability verdict and the remediation plan.
  3. Create (GitLab Duo): the issue triggers a custom Duo flow with three agents. Triage confirms it, fixer bumps the pin, adds a version floor and a regression test and opens the MR, and an independent reviewer must label it medic::ready. A second flow, the Pipeline Doctor, repairs a failed fix pipeline (at most 2 commits, then it escalates). An MCP server (osv_query, osv_scan_lockfile) gives the agents direct OSV lookups.
  4. Verify: 71 unit and integration tests (JUnit), CI and Duo flow YAML lint.
  5. Secure: GitLab SAST, Secret Detection, Dependency Scanning and an OSV re-check of the branch.
  6. Package: container image in the GitLab registry, CycloneDX SBOM, Container Scanning.
  7. Configure: version-controlled environment config and feature flags, config hash for audit, Terraform validation.
  8. Release: staging, health check, production canary, health check, production promote, GitLab Release.
  9. Monitor + Govern: post-deploy error-rate and latency checks with automatic rollback to the last good deployment (and the issue reopened), then an audit report and a one-page remediation receipt on GitLab Pages with the advisories, a per-stage timeline from real job times, scan results, SBOM diff and release health.

Guardrails replace human approvals: agents have no merge tool; a path allow-list blocks any agent change to CI, scanners or deploy code; nothing merges on red tests, HIGH/CRITICAL findings, a leaked secret or a remaining advisory; and production never stays degraded.

How we built it

  • GitLab Duo Agent Platform: two custom flows in .gitlab/duo/flows/ (zero-day-medic-fix: triage -> fixer -> reviewer; zero-day-medic-pipeline-doctor), agent-config.yml for the flow execution image and network policy, AGENTS.md rules every agent follows, a custom agent card, and an MCP client config pointing at our stdio OSV MCP server.
  • GitLab CI/CD: a 12-stage .gitlab-ci.yml with watch, MR and release pipeline shapes, GitLab security templates, GitLab environments, Releases and Pages.
  • Python scripts for each step: osv_watch, open_issue, reachability, guardrail_gate, auto_merge, canary_check, rollback, audit_report, render_receipt, metrics.
  • A small FastAPI "patient" service that deliberately pins vulnerable versions, plus an npm package-lock.json adapter so one watch run covers PyPI and npm.
  • Public project: https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/42360051/showcase. Release pipeline 2982651790 on main passed every stage; the receipt is at https://showcase-a2ed6c.gitlab.io/.

Challenges

  • Hands-off without being reckless. The hard part was not the automation but deciding what an agent must never be able to do, and enforcing that in CI rather than in a prompt.
  • Routing between agents. Branching on an LLM's free-text answer is brittle, so the fix flow is linear and each agent is told to no-op on SKIP.
  • Evidence without secrets. The audit report first showed an empty stage timeline on dry-run pipelines; we changed it to read the public jobs API anonymously so the receipt carries real job times without a write token.
  • Small CI surprises, such as git missing from the slim Python image, which broke the first pipeline run.

Accomplishments

  • All 9 stages pass on real GitLab CI, with rollback jobs wired in and skipped because the canary stayed healthy.
  • A remediation receipt anyone can open and check: CVE, scans, SBOM, rollout health and stage timings.
  • 71 offline tests, including an end-to-end rehearsal of the whole loop from advisory to issue, fix, gate, canary, rollback and audit.
  • Multi-ecosystem watch (PyPI and npm) and a no-fix-available mitigation path.

What we learned

  • Guardrails belong in the pipeline, not in the agent's instructions: an allow-list and a merge gate are easier to trust than a well-written prompt.
  • An independent reviewer agent plus a loop cap keeps agent work bounded and explainable.
  • Audit evidence is a product feature: time-to-remediate numbers and a receipt make the automation reviewable by people who never open the pipeline.

What's next

  • More ecosystems (poetry and uv lockfiles) and a Node side-service so one run fixes two ecosystems.
  • Real cloud traffic splits and revision-pinned rollback on the cloud deploy target.
  • Reading upstream changelogs before a major-version bump.
  • Firing the Duo fix flow live from a real watch-opened issue in the hackathon group (see limits).

Honest limits: staging, canary and production currently run as containers started inside CI (the default ci-service deploy target), not on external infrastructure; the cloud deploy target and its Terraform are written and validated but not applied. The full CVE -> issue -> Duo fix MR -> auto-merge path is rehearsed in the offline test suite; the Duo flows are defined in the repo (custom flows are created in the GitLab UI from these files), and the live pipeline shown in the demo is the release path on main. Sustainability numbers in docs/SUSTAINABILITY.md are stated assumptions, not measurements.

Built With

  • cyclonedx
  • docker
  • fastapi
  • gitlab
  • gitlab-ci
  • gitlab-duo
  • gitlab-pages
  • mcp
  • osv
  • pytest
  • python
  • terraform
Share this project:

Updates

Submission history