On December 9, 2021, the Log4Shell vulnerability (CVE-2021-44228) was publicly disclosed. Within 9 minutes, the first exploitation attempts appeared in honeypot logs. Within 24 hours, mass scanning was underway across the entire IPv4 address space. Within 72 hours, ransomware groups had integrated the exploit into their toolkits.
The organisations that avoided catastrophic damage had one thing in common: they could identify exposure and deploy patches in hours, not days. Not because they had better engineers — because they had better automation.
In 2026, the gap between CVE disclosure and active exploitation has shrunk further. The average time from public disclosure to first exploitation attempt is now measured in minutes for critical vulnerabilities. Your patching process needs to match that speed. This article describes the infrastructure that makes 2-hour patching possible.
Why Speed Matters: The Attack Surface Window
Every minute between CVE disclosure and patch deployment is an open window. During that window:
- Automated scanners are probing your external endpoints for the vulnerability
- Exploit kits are being updated with the new CVE — often within hours of disclosure
- Your SBOM tells you exactly which products and services are affected — if you have one
- Your competitors who patch first are no longer targets — attack traffic concentrates on those who haven't
Under the CRA, you must report actively exploited vulnerabilities to ENISA within 24 hours. Under DORA, financial entities must demonstrate that ICT risk management includes timely patching. Under NIS2, essential entities must ensure vulnerability handling without undue delay. "We'll patch it next sprint" is not a compliant response to a critical CVE.
The 2-Hour Patching Pipeline
Minute 0–15: Automated Detection
You can't patch what you don't know about. Detection must be automatic and immediate:
# Continuous vulnerability scanning (runs every 15 min via CronJob)
# Scans all SBOMs in the artifact registry against live CVE feeds
apiVersion: batch/v1
kind: CronJob
metadata:
name: sbom-vulnerability-scan
namespace: security-ops
spec:
schedule: "*/15 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: scanner
image: anchore/grype:latest
command:
- /bin/sh
- -c
- |
for sbom in /sboms/*.cdx.json; do
grype sbom:$sbom --fail-on critical --output json > /results/$(basename $sbom .cdx.json)-vulns.json
done
volumeMounts:
- name: sbom-store
mountPath: /sboms
readOnly: true
- name: results
mountPath: /results
Parallel detection channels:
- SBOM scanning: Grype or Trivy against your stored SBOMs — catches known CVEs in your dependency tree
- Image scanning: Registry-integrated scanning (Harbor, ECR, GCR) — catches OS-level vulnerabilities in your container base images
- GitHub Dependabot / Renovate: Automatically opens PRs when dependency updates are available
- Vendor advisory feeds: Direct subscription to Red Hat, Ubuntu, NVIDIA, and your critical vendor security feeds
Minute 15–30: Automated Impact Assessment
Detection fires an alert. Now you need to know: what's affected and how badly?
# Automated impact assessment script
# Triggered by webhook from vulnerability scanner
#!/bin/bash
CVE_ID=$1
SEVERITY=$2
# Query all SBOMs for the affected package
affected=$(sbom-query --cve "$CVE_ID" --format json)
# Determine which environments run affected images
for product in $(echo "$affected" | jq -r '.[].product'); do
environments=$(kubectl get pods --all-namespaces -o jsonpath="{.items[?(@.spec.containers[*].image=='$product')].metadata.namespace}" 2>/dev/null)
echo "Product: $product | Environments: $environments | Severity: $SEVERITY"
done
# Auto-escalate critical CVEs
if [ "$SEVERITY" = "critical" ]; then
pagerduty-trigger --severity=critical --summary="Critical CVE $CVE_ID affects production" --details="$affected"
fi
Minute 30–60: Automated Patch and Test
For dependencies managed by Renovate or Dependabot, the PR already exists. The automation pipeline:
- Dependency update: Renovate/Dependabot PR bumps the vulnerable dependency to the patched version
- Automated build: CI pipeline builds the new container image with the patched dependency
- SBOM regeneration: New SBOM generated from the patched image — verify the CVE no longer appears
- Test suite: Full test suite runs — unit, integration, contract tests. If tests pass, the image is signed and pushed
- Security gate: Final vulnerability scan of the new image. Zero critical CVEs or the pipeline blocks
# Emergency patch pipeline (GitHub Actions)
name: Emergency Security Patch
on:
pull_request:
labels: [security-critical]
jobs:
emergency-patch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build patched image
run: docker build -t $IMAGE:patched-${{ github.sha }} .
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: $IMAGE:patched-${{ github.sha }}
format: cyclonedx-json
output-file: sbom.cdx.json
- name: Verify CVE resolved
run: |
grype sbom:sbom.cdx.json --fail-on critical
echo "CVE verification passed"
- name: Run test suite
run: npm test
- name: Sign and push image
run: |
cosign sign --key env://COSIGN_KEY $IMAGE:patched-${{ github.sha }}
docker push $IMAGE:patched-${{ github.sha }}
- name: Auto-merge if all checks pass
if: success()
run: gh pr merge --auto --squash
Minute 60–90: Automated Deployment
The patched image is built, tested, signed, and pushed. Now it needs to reach production:
- GitOps update: ArgoCD or Flux detects the new image tag in the Git repository and begins the rollout
- Canary deployment: The patched version deploys to a canary (5% of traffic) first. Automated health checks monitor error rates, latency, and resource usage
- Progressive rollout: If canary metrics are healthy after 10 minutes, roll to 25%, then 50%, then 100%. Argo Rollouts or Flagger automates this
- Automatic rollback: If error rates spike during rollout, automatically revert to the previous version. The patch introduced a regression — fix it and try again
# Argo Rollout with canary strategy for emergency patches
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-service
spec:
strategy:
canary:
steps:
- setWeight: 5
- pause: { duration: 10m }
- setWeight: 25
- pause: { duration: 10m }
- setWeight: 50
- pause: { duration: 5m }
- setWeight: 100
analysis:
templates:
- templateName: error-rate-check
startingStep: 1
Minute 90–120: Verification and Communication
The patch is deployed. Now verify and communicate:
- Post-deploy SBOM scan: Scan the running production images to confirm the vulnerable version is no longer present anywhere in the cluster
- VEX update: Update the VEX document: status changed from "affected" to "fixed", referencing the patched version and deployment timestamp
- ENISA notification update: If you filed a 24h early warning, update it with remediation details
- Customer advisory: For on-premise customers, publish a security advisory with the patched version and upgrade instructions
- Internal retrospective ticket: Create a ticket to review the patch process — what went well, what was slow, what should be automated next
Kubernetes Recipes
A practical guide for container orchestration and deployment by Grzegorz Stencel & Luca Berton (Apress).
Watch on Skillshare →Minimising the Attack Surface Before the CVE
The fastest patch is the one you don't need. Attack surface reduction means fewer components to patch:
- Distroless base images: Use
gcr.io/distrolessor Chainguard images. No shell, no package manager, no unnecessary OS packages. Your SBOM shrinks from hundreds of packages to dozens - Multi-stage builds: Build dependencies stay in the build stage. Runtime images contain only the compiled application and its runtime dependencies
- Dependency minimisation: Audit your dependency tree quarterly. Every dependency is an attack surface. If you can replace a library with 50 lines of code, do it
- Unused port closure: If your application only listens on port 8080, your container shouldn't expose any other ports. NetworkPolicies should only allow traffic to that port
- Feature flag decomposition: Unused features that are still deployed are unnecessary attack surface. Feature flags let you disable code paths without redeployment — but dead code should eventually be removed
The Automation Maturity Ladder
Most organisations can't go from manual patching to 2-hour automation overnight. Here's the progression:
| Level | Detection | Patching | Deployment | Typical Time |
|---|---|---|---|---|
| 1. Manual | Email newsletters | Manual dependency update | Manual deployment | Days to weeks |
| 2. Alerted | Automated scanning | Manual dependency update | Manual deployment | 1–3 days |
| 3. Semi-automated | Automated scanning | Renovate/Dependabot PRs | Manual approval + deploy | 4–12 hours |
| 4. Automated | Continuous scanning | Auto-merge security PRs | Canary + progressive rollout | 1–2 hours |
| 5. Predictive | Pre-disclosure intelligence | Pre-built patches for likely CVEs | Instant rollout | Minutes |
Level 4 is the target for CRA/DORA/NIS2 compliance. Level 5 is where the most mature security organisations operate — monitoring pre-disclosure channels and preparing patches before CVEs are public.
Operationalizing ML Models: MLOps for Scalable AI
Turn ML prototypes into robust, scalable systems using real-world tools. In collaboration with Starweaver.
Start on Coursera →What Open Empower Delivers
We build the automated patching infrastructure that gets regulated enterprises to Level 4:
- SBOM-driven detection: Continuous scanning of your entire software inventory against live CVE feeds
- Emergency patch pipelines: Fast-track CI/CD paths that build, test, sign, and deploy security patches in under 2 hours
- Progressive deployment: Canary rollouts with automated health checks and instant rollback
- Attack surface reduction: Base image hardening, dependency minimisation, and NetworkPolicy implementation
- Compliance evidence: Automated VEX generation, ENISA notification templates, and patch audit trails for DORA/NIS2/CRA
The next critical CVE is coming. The only question is whether your patching pipeline is ready. Let's build it.
Luca Berton
