Het security-embargo is dood: patchen in het tijdperk van AI-exploits

AI-agents bouwen een werkende exploit uit alleen het gerucht van een bug. Wat dat betekent voor je .NET-patchpipeline, en wat je maandag kunt regelen.

Jean-Pierre Broeders

Freelance .NET Developer

31 augustus 202612 min. leestijd
Het security-embargo is dood: patchen in het tijdperk van AI-exploits

Anil Madhavapeddy, maintainer van de OCaml-bibliotheek cohttp, kreeg een privémelding van een bug via Slack. Hij deed wat elke nette maintainer doet: hij opende een publieke PR met de fix. Ongeveer tien minuten later verschenen de eerste geautomatiseerde probes op zijn servers, gericht op precies de percent-encoded traversal-sequences die de PR aanpakte. Niemand had een proof-of-concept gepubliceerd. Die was er niet eens. De diff was genoeg.

Zijn conclusie staat in de titel van zijn post: het gerucht van een bug is tegenwoordig genoeg om een exploit te vinden. Ik las het, dacht aan een paar van mijn eigen klanten, en werd stil.

Want dit raakt niet de theorie van security. Dit raakt de manier waarop wij allemaal patchen. En dat proces is bij de meeste teams die ik binnenkom nog steeds gebouwd op een aanname die net is verlopen.

De aanname die kapot is

Jarenlang draaide responsible disclosure op een impliciete deal. Een onderzoeker vindt een bug, meldt hem privé, en de maintainer krijgt een venster. Zeg negentig dagen. In dat venster bouw je de fix, test je, en rol je uit voordat de details openbaar worden. Het embargo gaf je tijd. De aanvaller moest zelf het werk doen om van een vage advisory naar een werkende exploit te komen, en dat werk was traag genoeg dat het venster iets waard was.

Dat werk is nu bijna gratis.

Anil verwijst naar het onderzoek van Fang en collega's. Zij gaven een GPT-4-agent van 91 regels code toegang tot vijftien echte one-day-kwetsbaarheden, samen met de CVE-beschrijving. De agent bouwde in 87 procent van de gevallen een werkende exploit. Haal je de CVE-beschrijving weg, dan zakt dat naar 7 procent. Lees dat verschil nog eens. De agent vindt de bug niet zelf, maar zodra hij een hint krijgt van waar hij moet kijken, is de exploit een kwestie van minuten.

En de hint hoeft geen CVE te zijn. Een dichtgetimmerde PR-titel als "fix path traversal in request handler" is een hint. Een changelog-regel is een hint. Een commit die opeens een extra ..-check toevoegt is een hint. Anil noemt DeepSeek V4 Pro, dat na een vraag over path-normalisatie zelf meerdere gerelateerde bugs vond en er een exploit voor schreef om een lokale server te bestoken, in minder dan een minuut.

De cijfers die hij noemt zijn ronduit ongemakkelijk. De marimo-kwetsbaarheid CVE-2026-39987 ging van advisory naar eerste exploitatiepoging in negen uur, zonder dat er ooit een PoC bestond. En de gemiddelde tijd tot exploit is volgens hem inmiddels min zeven dagen. De aanval komt gemiddeld dus vóór de patch.

Waarom dit een .NET-probleem is, niet iemand anders zijn probleem

Je zou dit kunnen wegzetten als een probleem van open-source maintainers. Dat is het niet. Jij draait NuGet-packages die door precies zulke maintainers worden onderhouden. Op het moment dat een van die packages een security-fix pusht, is de wedstrijd al bezig. De vraag is niet meer of jij het embargo-venster haalt. Er is geen venster.

De vraag is: hoe snel kan jouw team van "er is een fix" naar "die fix draait in productie"? Als dat antwoord in dagen of weken wordt gemeten, dan is dat je nieuwe blootstellingsvenster. Niet de negentig dagen van de onderzoeker. Jouw eigen doorlooptijd.

Ik heb teams gezien waar een dependency-update door drie approvals moet, een handmatige QA-cyclus, en een release-window dat één keer per sprint opengaat. In het oude model was dat traag maar verdedigbaar. In dit model is het een open deur die je zelf twee weken laat openstaan.

Dus laten we praten over wat je maandag kunt doen. Geen abstracte principes, gewoon dingen die werken.

Ken wat je draait

Je kunt niet patchen wat je niet in beeld hebt. De eerste stap is banaal en wordt bijna altijd overgeslagen: weet welke kwetsbare packages je nu op dit moment in je oplossing hebt, inclusief de transitieve.

dotnet list package --vulnerable --include-transitive

Die --include-transitive is het punt. De meeste teams checken hun directe dependencies en missen dat de echte bug drie lagen diep zit, in een package waar je nog nooit van hebt gehoord maar die via een via via wordt binnengetrokken. Draai dit lokaal, en draai het daarna in CI zodat het niet van iemands discipline afhangt.

Een SBOM erbij helpt als je meerdere services draait. Met de Microsoft.Sbom.Tool genereer je een CycloneDX- of SPDX-lijst van alles wat er in een build zit, zodat je bij de volgende paniekmelding binnen minuten weet welke van je twaalf services die ene package eigenlijk gebruikt. Zonder SBOM is dat antwoord een middag grep-werk. Met SBOM is het een query.

Automatiseer de update-loop, en laat CI hem tegenhouden

Een update die op een mens wacht, wacht te lang. Zet Dependabot of Renovate aan en laat security-updates automatisch een PR openen. Renovate laat je onderscheid maken tussen gewone version bumps en vulnerability fixes, en dat onderscheid is precies wat je wilt: de meeste updates mogen rustig gegroepeerd wachten, maar een security-fix moet vooraan in de rij.

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended"],
  "vulnerabilityAlerts": {
    "labels": ["security"],
    "automerge": true,
    "schedule": ["at any time"]
  },
  "packageRules": [
    {
      "matchUpdateTypes": ["minor", "patch"],
      "groupName": "non-security updates",
      "schedule": ["before 6am on monday"]
    }
  ]
}

De vulnerabilityAlerts met automerge is de kern. Een security-PR die door je tests komt, mag zichzelf mergen, op elk moment van de dag. Je gewone updates parkeer je in een wekelijkse batch zodat de ruis je niet gek maakt. En dan de vangrail: laat je pipeline falen als er een bekende high of critical in zit die je nog niet hebt gepatcht.

name: dependency-scan
on:
  pull_request:
  schedule:
    - cron: "0 6 * * *"
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "9.0.x"
      - name: Restore
        run: dotnet restore
      - name: Fail on vulnerable packages
        run: |
          dotnet list package --vulnerable --include-transitive 2>&1 | tee scan.txt
          if grep -E "Critical|High" scan.txt; then
            echo "::error::Kwetsbare package met High/Critical severity gevonden"
            exit 1
          fi

Dit is geen sluitende security-scan. Het is een rookmelder. Maar een rookmelder die elke ochtend om zes uur afgaat en elke PR blokkeert, is oneindig veel waard vergeleken met een team dat pas naar dotnet list package grijpt als het al brandt.

Deploy-snelheid is nu een security-eigenschap

Hier zit voor de meeste teams de echte klap. Je kunt de snelste dependency-scan ter wereld hebben, maar als een merge naar main pas over negen dagen in productie staat, heb je niks opgelost. Je blootstellingsvenster is je deploy-doorlooptijd, punt.

Dat maakt een saai onderwerp opeens dringend. Continuous deployment, een groene main die je op elk moment durft uit te rollen, een rollback die in seconden werkt in plaats van een change-ticket van een uur. Dat waren altijd al goede ideeën. Nu zijn het security-maatregelen.

Feature flags horen in dat rijtje. Als je een verdachte endpoint in productie hebt en de fix nog een uur duurt, wil je die endpoint kunnen dichtzetten zonder een release. Een simpele flag-check kost je bijna niks en geeft je een noodrem.

app.MapPost("/api/import", async (ImportRequest req, IFeatureManager features) =>
{
    if (!await features.IsEnabledAsync("LegacyImport"))
        return Results.StatusCode(StatusCodes.Status503ServiceUnavailable);

    // ... normale afhandeling
    return Results.Ok();
});

Zet die flag centraal, en je kunt een kwetsbaar pad uitschakelen terwijl je de echte fix rustig bouwt. Geen paniekdeploy om half twaalf 's nachts.

Verdedig aan de rand, niet alleen in de fix

De exploits die Anil beschrijft mikken vaak op klassiekers: path traversal, percent-encoding-trucs, dubbele decoding. Dat zijn precies de dingen die je aan de rand van je applicatie kunt afvangen voordat een request ooit bij je businesslogica komt. Vertrouw nooit op een pad dat van buiten komt.

static bool IsSafePath(string root, string userInput)
{
    var combined = Path.Combine(root, userInput);
    var fullPath = Path.GetFullPath(combined);
    var fullRoot = Path.GetFullPath(root);

    return fullPath.StartsWith(fullRoot + Path.DirectorySeparatorChar,
        StringComparison.Ordinal);
}

De truc zit in Path.GetFullPath, dat ..-segmenten normaliseert voordat je vergelijkt. Iemand die ../../etc/passwd of een dubbel-encoded variant meestuurt, valt buiten je root en wordt geweigerd. Combineer dit met rate limiting op je gevoelige endpoints, want een AI-agent die exploits aan het aftasten is genereert een herkenbaar patroon van mislukte pogingen.

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("sensitive", opt =>
    {
        opt.PermitLimit = 10;
        opt.Window = TimeSpan.FromSeconds(30);
        opt.QueueLimit = 0;
    });
});

Dit stopt een vastberaden aanvaller niet, maar het verhoogt de kosten en het geeft je logs iets om op te alarmeren. En alarmering is het punt: als je die tien-minuten-probes van Anil op je eigen servers ziet aankomen, wil je daar een melding van, geen ontdekking achteraf in de logs van vorige week.

Ga ervan uit dat er iets doorheen komt

Rotatie van secrets hoort in dit verhaal omdat de eerlijke aanname is dat je een keer geraakt wordt. Als dat gebeurt, wil je dat de schade een houdbaarheidsdatum heeft. Kortlevende tokens, credentials die automatisch roteren, een sleutel die je binnen een uur kunt intrekken zonder een deploy. Azure Key Vault met managed identities regelt het meeste hiervan, en het verschil tussen "we moeten alle secrets handmatig vervangen" en "de rotatie draaide vannacht al" is het verschil tussen een incident en een voetnoot.

Denk ook aan de andere kant van je pipeline. Als een aanvaller via een kwetsbare dependency binnenkomt in je build-omgeving, dan zijn je CI-secrets het doelwit. Gebruik OIDC in plaats van langlevende cloud-credentials in je GitHub Actions, zodat er geen statische sleutel is om te stelen. Een token dat na de job verloopt, is een token dat een aanvaller niet kan hergebruiken.

De keerzijde is dat jij dezelfde tools hebt

Het is makkelijk om hier somber van te worden, dus even de andere kant. Dezelfde agentische tools die exploits schrijven, kunnen jouw diffs lezen voordat ze publiek gaan. Ik gebruik een model steeds vaker als een tweede paar ogen op een security-fix: "welke informatie lekt deze PR-titel, en hoe zou iemand die misbruiken?" Dat is precies de vraag die de aanvaller stelt, dus stel hem eerst.

Diezelfde agents kunnen je legacy-code aftasten op de patronen die nu in het vizier liggen, testcases genereren rond je invoervalidatie, en je patch-PR's reviewen op regressies. De asymmetrie is reëel, want de verdediger moet elke deur dichthouden en de aanvaller hoeft er maar één te vinden. Maar de tooling is niet exclusief voor de aanvaller. De teams die dit overleven zijn de teams die de loop van detectie naar patch naar deploy net zo hard automatiseren als de aanvaller zijn exploit-generatie automatiseert.

Veelgestelde vragen over AI-exploits en je patchpipeline

Betekent dit dat responsible disclosure zinloos is geworden? Nee, maar het venster dat het je gaf is grotendeels weg. Privémelding blijft nuttig om de maintainer eerst te laten fixen, alleen moet je er niet meer van uitgaan dat je dagen of weken hebt tussen de publieke fix en de eerste exploitatiepoging. Behandel elke security-PR als een halfopenbare aankondiging van waar de bug zit.

Hoe snel moet ik een security-update in productie hebben? Zo snel als je pipeline betrouwbaar toestaat, en de eerlijke doelstelling is uren, niet dagen. De concrete cijfers uit Anil's post laten exploitatie zien binnen negen uur en probes binnen tien minuten na een publieke fix, dus je doorlooptijd van merge naar productie is nu je feitelijke blootstellingsvenster.

Is dotnet list package --vulnerable genoeg als security-scan? Nee, het is een rookmelder, geen alarmsysteem. Het vangt bekende kwetsbaarheden in je NuGet-graaf af, inclusief transitieve, maar het zegt niets over je eigen code, je configuratie of onbekende bugs. Gebruik het als eerste vangrail in CI en vul het aan met static analysis en een echte dependency-scanner.

Moet ik automerge echt aanzetten op security-PR's? Alleen als je testsuite en je deploy-pipeline betrouwbaar genoeg zijn dat je ze op zes uur 's ochtends durft te vertrouwen zonder mens erbij. Zo niet, dan is dat je eigenlijke werk: niet de automerge, maar de tests en de rollback die automerge veilig maken. Begin met automerge voor patch-level security-fixes en breid uit als je vertrouwen groeit.

Verder lezen


Conclusie: Je blootstellingsvenster is niet langer het embargo van de onderzoeker, maar je eigen doorlooptijd van merge naar productie. Meet die, verkort hem, en automatiseer de weg van detectie naar deploy net zo agressief als de aanvaller zijn exploit-generatie automatiseert.

Bronnen: Rumour is the exploit (Anil Madhavapeddy) · Hacker News-discussie.

Wil je op de hoogte blijven?

Schrijf je in voor mijn nieuwsbrief of neem contact op voor freelance projecten.

Neem Contact Op