Het incident met repositoryuploads van ZCode gaat verder dan één codeertool. Het legt een beveiligingsvraag bloot die ontwikkelaars steeds vaker moeten beantwoorden voordat ze een AI-agent toegang geven tot een project: betekent “toegang tot de repository” het huidige bestand, de werkboom of jaren aan Git-geschiedenis?
Dat onderscheid is belangrijk, omdat .git informatie kan bevatten die niet langer zichtbaar is in de huidige codebase, waaronder verwijderde geheimen, oude bronversies, reflogs, LFS-middelen en de lokale branchgeschiedenis. ZCode zegt dat het betreffende uploadgedrag is verholpen, maar het incident laat een blijvende les achter: AI-codeeragenten hebben expliciete gegevensgrenzen nodig, niet alleen toestemming om “toegang tot de repo” te krijgen.
Wat gebeurde er werkelijk met ZCode?
Op 18 september 2026 publiceerde ontwikkelaar ferstar een reverse-engineeringonderzoek naar ZCode 3.12.3, nadat hij onverwacht grote bestanden in de lokale gegevensmap van de applicatie had opgemerkt.
Volgens het oorspronkelijke onderzoek maakte de client versleutelde worksamples die zowel bronbestanden als .git, Git LFS-objecten, reflogs en repositorymetagegevens konden bevatten. De client bevatte ook een pipeline voor het verkrijgen van uploadreferenties en het verzenden van versleutelde archieven naar Alibaba Cloud OSS.
ZCode erkende vervolgens uploads van repositorygegevens die verband hielden met het indexeren van codebases en Repo Wiki, bood excuses aan, zei dat het gedrag was verholpen en kondigde plannen aan voor opensource- en externe beoordeling. In de berichtgeving uit die periode werden de belangrijkste punten van ZCodes reactie opnieuw weergegeven.
| Bewering | Bewijs |
|---|---|
| Oudere ZCode-versies maakten brede repositorysnapshots | Ondersteund door reverse-engineering en lokaal snapshotbewijs |
| Er bestond een uploadpipeline | Ondersteund door reverse-engineering van het clientgedrag |
| Een kleine repository heeft de service succesvol bereikt | Bevestigd door de vervolgtest van de onderzoeker |
| De commerciële repository van 313 MB is succesvol geüpload | Nee - die upload is mislukt |
| De huidige ZCode gebruikt nog steeds dezelfde pipeline | Geen bewijs; de onderzoeker meldt dat het oude pad is verwijderd |
Dit is het eerste belangrijke informatiegat dat moet worden gedicht: het incident was echt, maar sommige virale samenvattingen overdreven wat er daadwerkelijk succesvol was overgedragen.
Is de privérepository van 313 MB daadwerkelijk geüpload?
Nee.
De snapshot van het commerciële project bevatte ongeveer 42.000 bestanden en resulteerde in een versleuteld archief van ongeveer 313 MB. Volgens de update van de onderzoeker van 19 september bleef deze lokaal in behandeling status after 564 failed attempts because it exceeded the uploadlimiet. ([blog.ferstar.org](https://blog.ferstar.org/en/posts/zcode-silent-workspace-snapshot-upload/))
Een afzonderlijke, kleinere openbare repository bereikte de dienst wel. Deze bevatte 538 bestanden en leverde een veel kleinere versleutelde payload op.
| Repository | Waargenomen resultaat |
|---|---|
| 313MB commerciële repository | Lokaal verpakt, herhaaldelijk geprobeerd, upload mislukt |
| Kleine openbare repository | Succesvol geaccepteerd door de externe dienst |
De juiste conclusie is daarom niet “elke ZCode-repository is geüpload”. De conclusie is dat de oude client een functioneel mechanisme voor het uploaden van repositories bevatte, waarvan het daadwerkelijke succes afhankelijk was van de snapshot.
Waarom de map `.git` het belangrijkste onderdeel van dit incident is
In de grote snapshot van de onderzoeker bestond het grootste deel van de payload niet uit de huidige broncode.
| Snapshotinhoud | Geschat aandeel |
|---|---|
.git/lfs/ |
56.8% |
.git/objects/ |
29.6% |
.git/logs/ |
0.2% |
| Huidige broncode en documentatie | 13.4% |
Dat betekent dat ongeveer 86.6% van de snapshot uit .git kwam. ([blog.ferstar.org](https://blog.ferstar.org/en/posts/zcode-silent-workspace-snapshot-upload/))
Dit verandert de beveiligingsinterpretatie volledig.
Een AI-agent die de huidige bronboom leest, ziet mogelijk wat de ontwikkelaar tegenwoordig bewust bewaart. Toegang tot de Git-geschiedenis kan onthullen wat de ontwikkelaar dacht al te hebben verwijderd.
Mogelijke historische blootstelling omvat:
- verwijderde bronbestanden
- oude API-sleutels of tokens
- eerdere interne eindpunten
- verlaten functies
- historische configuratie
- lokale branchactiviteit
- toestanden die alleen in de reflog voorkomen
- grote historische LFS-assets
De Git-reflogdocumentatie legt uit dat reflogs eerdere waarden van lokale verwijzingen vastleggen. Die records kunnen lokaal bestaan, zelfs wanneer de bijbehorende geschiedenis nooit naar een externe repository is gepusht.
Dit geeft ons een nuttige beveiligingsregel:
“Mijn project lezen” en “mijn Git-geschiedenis lezen” zouden afzonderlijke machtigingen moeten zijn.
Waarom verwijderde geheimen nog steeds kunnen bestaan nadat je ze uit de code hebt verwijderd
Het verwijderen van inloggegevens uit het nieuwste bestand verwijdert ze niet noodzakelijkerwijs uit Git.
Een ontwikkelaar kan per ongeluk een API-sleutel vastleggen, deze in de volgende commit verwijderen en een volledig schoon huidig bestand zien. Het eerdere blob-object kan via de repositorygeschiedenis nog steeds bereikbaar zijn.
De richtlijnen van GitHub voor het verwijderen van gevoelige gegevens bevelen expliciet aan om blootgelegde inloggegevens in te trekken of te rouleren voordat de geschiedenis wordt herschreven.
Die volgorde is belangrijk:
- Maak de inloggegevens ongeldig.
- Verwijder gevoelige geschiedenis waar dat gepast is.
- Voorkom dat het geheim opnieuw wordt vastgelegd.
Voor AI-codeagents betekent dit dat een functie die rekening houdt met de geschiedenis toegang kan krijgen tot gegevens die een normale editorweergave niet langer toont.
Dit verklaart ook waarom een alleen-lezen-agent niet automatisch een laag risico inhoudt. Alleen-lezen-toegang kan nog steeds waardevolle informatie lekken als het bereik van het bestandssysteem te groot is of als opgehaalde inhoud naar een extern model wordt verzonden.
Modelcontext, telemetrie, training en uploads van repositories zijn niet hetzelfde
Een andere belangrijke les is dat één enkele schakelaar voor “privacy” niet elk type gegevensstroom kan vertegenwoordigen dat een AI-codeertool kan hebben.
| Gegevensstroom | Typisch doel |
|---|---|
| Inferentiecontext | Code verzenden die nodig is om de huidige taak te beantwoorden |
| Telemetrie | Crashes, betrouwbaarheid en gebruik meten |
| Gegevens voor modeltraining | Toekomstige modellen of productgedrag verbeteren |
| Repository-index | Een project efficiënter doorzoeken en begrijpen |
| Cloudsnapshot | Een bredere werkruimtestaat behouden |
| Synchronisatie / back-up | Gegevens tussen sessies of apparaten herstellen |
De betreffende ZCode-versie is belangrijk omdat de onderzoeker meldde dat het uitschakelen van de optie voor optimalisatie/training de afzonderlijke snapshot-pijplijn niet uitschakelde. In het rapport werd ook beweerd dat de schakelaar voor Repo Snapshot Indexing in die versie niet verhinderde dat er pogingen werden gedaan om pakketten te maken en te uploaden. ([blog.ferstar.org](https://blog.ferstar.org/en/posts/zcode-silent-workspace-snapshot-upload/))
Dit leidt tot een regel die veel verder gaat dan ZCode:
“Train niet op mijn gegevens” betekent niet “verzend mijn gegevens niet”.
Een cloudmodel heeft nog steeds context voor inferentie nodig. Telemetrie kan via een ander eindpunt worden verstuurd. Synchronisatie kan een andere kopie bewaren. Het indexeren van de repository kan een eigen gegevensstroom hebben.
Hetzelfde onderscheid doet zich voor wanneer een lokale AI-agent cloudtools gebruikt: privacy hangt af van de exacte gegevens die de grens overgaan, niet simpelweg van waar het hoofdproces van de agent draait.
Versleuteling beantwoordt de belangrijkste privacyvraag niet
De betreffende ZCode-snapshot werd vóór het uploaden versleuteld.
Het reverse-engineeringrapport beschrijft AES-256-CTR-versleuteling voor het archief en RSA-OAEP-SHA256-wrapping voor de symmetrische sleutel. De openbare RSA-sleutel werd door de dienst verstrekt, terwijl de bijbehorende privésleutel niet lokaal was opgeslagen. ([blog.ferstar.org](https://blog.ferstar.org/en/posts/zcode-silent-workspace-snapshot-upload/))
Dat beschermt gegevens op een andere manier dan end-to-end-versleuteling die door de gebruiker wordt beheerd.
| Bescherming | Wat het betekent |
|---|---|
| TLS / transportversleuteling | Beschermt gegevens tijdens het transport over het netwerk |
| Cloudversleuteling bij opslag | Beschermt opgeslagen bytes tegen bepaalde infrastructuurbedreigingen |
| Door de provider beheerde sleutel | De dienst kan technisch gezien de mogelijkheid behouden om te ontsleutelen |
| Door de gebruiker beheerde end-to-end-sleutel | De dienst beschikt niet over de vereiste ontsleutelingssleutel |
Dus “de repository was versleuteld” is onvolledig.
De belangrijkere vraag is:
wie kan het ontsleutelen?
Datzelfde principe geldt voor private RAG, cloudback-ups, AI-geheugen en elk systeem dat beweert dat gegevens beschermd zijn omdat ze versleuteld zijn.
Hoeveel toegang tot een repository heeft een codeeragent daadwerkelijk nodig?
Codeeragents hebben legitiem meer context nodig dan traditionele autocomplete. Voor een refactor van de hele repository kunnen veel bestanden nodig zijn. Een debuggingagent kan tests, afhankelijkheidsmetadata, Git-status en builduitvoer nodig hebben.
Maar “de agent heeft mogelijk brede context nodig” betekent niet “elke functie moet elk byte in de repository ontvangen”.
| Gegevensscope | Verstandige standaardinstelling |
|---|---|
| Huidig bestand | Toestaan voor relevante taken |
| Gerefereerde bronbestanden | Toestaan |
| Volledige bronboom | Taakafhankelijk |
.gitignore-uitgesloten bestanden |
Uitsluiten |
.env / referenties |
Blokkeren |
.git objecten |
Uitsluiten tenzij expliciet vereist |
| Reflogs | Standaard uitsluiten |
| Git LFS-cache | Uitsluiten tenzij vereist |
| SSH-/cloudreferenties | Blokkeren |
| Volledige snapshot op afstand | Expliciete toestemming |
Dit is een versie van hetzelfde principe voor gegevenstoegang als in een vertrouwensgrens voor tooluitvoering: het vermogen van het model om iets aan te vragen mag niet automatisch de bevoegdheid verlenen om alles in de omgeving te openen of te exporteren.
Voor codeeragents hebben we twee onafhankelijke grenzen nodig:
- Actiegrens: wat kan de agent wijzigen of uitvoeren?
- Gegevensgrens: wat kan de agent lezen of verzenden?
Een agent zonder schrijfrechten kan nog steeds ernstige privacyrisico's veroorzaken als de lees- en netwerkrechten onbeperkt zijn.
Wat heeft ZCode na het incident veranderd?
Het incident moet niet worden beschreven alsof bekend is dat hetzelfde gedrag in huidige ZCode-versies voorkomt.
Bij een vervolginspectie van ZCode 3.14.0 meldde de onderzoeker dat de eerdere upload-sidecar was verwijderd en dat het oude credential-endpoint 404 retourneerde. Het geïnspecteerde pad behield lokale checkpointfunctionaliteit zonder het eerdere mechanisme voor uploaden op afstand. ([blog.ferstar.org](https://blog.ferstar.org/en/posts/zcode-silent-workspace-snapshot-upload/))
De huidige Repo Wiki-documentatie beschrijft ook een veel beperktere gegevensgrens.
Er staat dat de Wiki-context het volgende uitsluit:
.git- afhankelijkheidsmappen
- builduitvoer
- caches
- lokale runtime-status
- ondersteund
.gitignoreuitsluitingen - vermoedelijk gevoelige configuratiebestanden
- symlinkdoelen
De uitvoer van Repo Wiki wordt gedocumenteerd als lokale toepassingsgegevens en niet als inhoud die terug naar de repository wordt geschreven.
Dit verschilt wezenlijk van het snapshotgedrag dat in versie 3.12.3 werd gemeld.
Is open source voldoende om een codeeragent privé te maken?
Nee.
Open source kan het voor een klant eenvoudiger maken om een toepassing te controleren, maar een open-sourcetoepassing kan nog steeds broncode naar cloudmodellen sturen, telemetrie uploaden, status synchroniseren of afhankelijk zijn van opslag die door een provider wordt beheerd.
De nuttigere checklist is:
| Vraag | Beveiligingseigenschap |
|---|---|
| Wat kan de agent lezen? | Lokale gegevensscope |
| Wat kan de machine verlaten? | Grens voor uitgaand verkeer |
| Waarom wordt dit verzonden? | Doelbeperking |
| Hoelang worden ze bewaard? | Persistentie |
| Wie beheert de encryptiesleutels? | Ontsleutelingsbevoegdheid |
| Kan het gedrag worden uitgeschakeld? | Gebruikerscontrole |
| Kunnen buitenstaanders dit verifiëren? | Controleerbaarheid |
Daarom wordt een private AI-architectuur meer bepaald door de gegevensstroom dan door de vraag of de softwarelicentie toevallig open source is.
Hoe moeten ontwikkelaars een nieuwe AI-codeeragent controleren?
Ontwikkelaars hoeven niet elke app volledig te reverse-engineeren, maar een nieuwe agent mag niet als eerste testomgeving toegang krijgen tot een gevoelige commerciële repository.
- Lees de documentatie over gegevensverwerking. Maak onderscheid tussen inferentie, telemetrie, training, indexering, synchronisatie en back-ups.
-
Controleer uitsluitingsregels. Zoek specifiek naar
.git,.env, genegeerde bestanden, afhankelijkheden, inloggegevens en symbolische koppelingen. - Begin met een wegwerpbare repository. Gebruik eerst niet-gevoelige code.
- Inspecteer lokale app-opslag. Onverwacht grote caches of snapshots kunnen de verborgen reikwijdte van gegevens onthullen.
- Houd uitgaand verkeer in de gaten. Firewall-, DNS-, proxy- of routerlogboeken kunnen externe diensten identificeren.
- Gebruik onschadelijke canarybestanden. Test of niet-gerelateerde bestanden in de modelcontext of uploadcontext terechtkomen.
- Verleen eerst de minimaal benodigde bevoegdheden. Breid deze alleen uit wanneer een specifieke taak dat vereist.
Hier helpt ook agentontwerp volgens het principe van minimale bevoegdheden, zolang ‘alleen-lezen’ wordt gecombineerd met beperkte paden en gecontroleerde uitgaande gegevens, in plaats van onbeperkte zichtbaarheid van de repository.
Wat een lokaal-eerst codeeragent anders zou moeten doen
Lokaal-eerst betekent niet dat elke taak offline moet worden uitgevoerd.
Dit betekent dat lokale gegevens standaard binnen de lokale vertrouwensgrens blijven en externe verzending doelbewust plaatsvindt in plaats van incidenteel.
| Lokaal-eerstprincipe | Voorkeursgedrag |
|---|---|
| Repository-indexering | Houd symbolen, embeddings en metadata waar praktisch lokaal |
| Context van het externe model | Verstuur alleen code die relevant is voor de taak |
| Git-geschiedenis | Sluit ze uit, tenzij de taak expliciet om geschiedenis vraagt |
| Geheimen | Filter voordat je de context samenstelt |
| Externe upload | Toon de reikwijdte en vraag expliciete toestemming |
| Toestemming voor training | Scheid dit van de inferentiebevoegdheid |
| Gevoelige repositories | Bied volledig lokale paden voor modellen en indexering |
| Netwerkafhankelijkheid | Documenteer wat offline niet meer werkt |
Dit principe is breder dan coderen. Een echt lokale AI-workflow moet het kritieke datapad van begin tot eind lokaal houden; een lokaal geïnstalleerd model is niet voldoende als embeddings, indexering, authenticatie of bestandsverwerking stilletjes afhankelijk zijn van een externe dienst.
Voor hybride systemen is het sterkere patroon om privébestanden achter een lokale service te houden en alleen de minimaal vereiste context beschikbaar te stellen aan goedgekeurde externe tools. Dat is dezelfde aanpak die wordt gebruikt bij het ontwerpen van een agent die clouddiensten gebruikt zonder het volledige lokale bestandssysteem bloot te stellen.
De grotere les: toegang tot repositories is een beveiligingsmachtiging
De blijvende les van ZCode is niet: “gebruik nooit cloudcodeeragents”. Het is dat toegang tot repositories op zichzelf een beveiligingsmachtiging is geworden.
Een moderne codeeragent kan het volgende combineren:
- het lezen van volledige projecten
- Git-bewustzijn
- terminaluitvoering
- browsertoegang
- externe modellen
- achtergrondtaken
- langetermijngeheugen
- autonome bestandsbewerking
Dat betekent dat ontwikkelaars meer moeten beoordelen dan alleen welke opdrachten een agent kan uitvoeren.
Ze moeten zich ook afvragen:
- Welke bestanden kan het bekijken?
- Hoe ver terug in de geschiedenis kan het kijken?
- Welke van die gegevens verlaten de machine?
- Welke service ontvangt ze?
- Hoelang worden ze bewaard?
- Wie kan deze ontsleutelen?
Voor AI-codeeragents gaat privacy niet langer alleen over de vraag of het model op je code wordt getraind. Het gaat erom of de gegevensgrens van de agent overeenkomt met de taak die je daadwerkelijk hebt gevraagd uit te voeren.
Veelgestelde vragen over het incident met het uploaden van repositories door ZCode
Heeft ZCode de volledige privérepository van 313 MB van de onderzoeker geüpload?
Nee. De onderzoeker meldde dat de snapshot van het grote commerciële project was verpakt en herhaaldelijk in de uploadwachtrij was geplaatst, maar vanwege de omvang niet kon worden geüpload. Een afzonderlijke, kleinere openbare repository werd wel door de service geaccepteerd.
Kan `.git` geheimen bevatten die niet meer in de huidige code staan?
Ja. Git-objecten en historische commits kunnen eerdere versies van bestanden bewaren nadat gevoelige inhoud uit de werkmap is verwijderd. Reflogs kunnen ook lokale referentiegeschiedenis bevatten die mogelijk nooit op afstand is gepusht.
Stopt het uitschakelen van AI-training een codeeragent ervan om code te uploaden?
Niet noodzakelijk. Training, inferentie, het indexeren van repositories, telemetrie, cloudsynchronisatie en back-ups zijn afzonderlijke gegevensstromen. Het uitschakelen van toestemming voor modeltraining schakelt niet automatisch de gegevensoverdracht uit die voor een andere cloudfunctie vereist is.
Heeft ZCode het probleem met de repository-snapshot opgelost?
ZCode zegt dat het probleem is opgelost. De oorspronkelijke onderzoeker meldde dat het oude pad voor uploaden op afstand ontbrak in versie 3.14.0, terwijl de huidige Repo Wiki-documentatie expliciet uitsluit .git, afhankelijkheden, builduitvoer, caches en verschillende gevoelige bestandscategorieën uit de Wiki-modelcontext.
Is een AI-codeeragent met open source automatisch privé?
Nee. Open source verbetert de controleerbaarheid, maar privacy hangt nog steeds af van welke bestanden de tool leest, welke gegevens het apparaat verlaten, welke clouddiensten ze ontvangen, hoelang ze worden bewaard en wie de encryptiesleutels beheert.
Tech & AI HUB
Meer om te lezen

Wat het nog nooit heeft gezien? Talkie-1930 en de Einstein-test
Talkie-1930 test of AI kan generaliseren buiten zijn trainingsperiode en onderscheidt redeneren van memoriseren met een kennisgrens van 1930.

Gemini 3.8 Live uitgelegd: wanneer AI tegelijkertijd kan kijken, praten en nadenken
Gemini 3.8 Live combineert realtime spraak, beeld en redeneren op de achtergrond, waardoor lokale filtering en privacy belangrijker worden voor altijd actieve AI.

Grok 4.8 is een model van 2,5T - maar de nieuwe C++-stack is het grotere verhaal
Grok 4.8 combineert naar verluidt een model van 2,5 biljoen parameters met een nieuwe C++-trainingsstack en laat zien waarom frontier-AI steeds meer een infrastructuurwedstrijd...

