Wichtigste Erkenntnisse
- Die Hashes des Go-Moduls beziehen sich auf Dateinamen und Inhalte, nicht auf die ZIP-Kodierung, sodass ein unabhängig neu erstelltes Archiv exakt übereinstimmen kann.
- Aus diesem Grund führt die Konfiguration von GOPROXY auf eine gefilterte Registrierungsdatenbank nicht dazu, dass Ihre bereits vorhandenen „go.sum“-Einträge ungültig werden.
- Eine exakte Rekonstruktion beweist, dass ein Archiv mit seiner Quelle übereinstimmt, nicht aber, dass die Quelle sicher ist.
- Die Änderung selbst betrifft nur eine Umgebungsvariable, das eigentliche Risiko liegt jedoch in der Konfigurationsabweichung.
Im Juli 2026 brachten Forscher eine Welle von gehackten Betreuerkonten bei npm, Packagist und Go-Modules mit einer Kampagne in Verbindung, die mit Nordkorea in Verbindung steht und den Namen PolinRiderin Verbindung brachten. Im Rahmen dieser Kampagne wurden zwar auch brandneue schädliche Pakete veröffentlicht, doch besonders bemerkenswert ist, was mit bereits etablierten Paketen geschah. Die Angreifer verschafften sich Zugang zu Konten mit jahrelanger einwandfreier Historie und veröffentlichten von dort aus neue Versionen.
Eine neue Modulversion, die von einem kompromittierten Betreuerkonto hochgeladen wurde, kann bei der ersten Verwendung die Integritätsprüfungen von Go bestehen. Sowohl go.sum als auch die Prüfsummen-Datenbank bestätigen, dass Sie genau das erhalten haben, was veröffentlicht wurde. Keines der beiden Systeme äußert sich dazu, ob das Veröffentlichte sicher ist.
Das Hinzufügen einer Prüfschicht zu einem Build kann an manchen Stellen zu Reibungsverlusten führen. Neue Paketidentitäten, die abgeglichen werden müssen, Versionen, die im Auge behalten werden müssen, Änderungen an der Lock-Datei, mit denen niemand gerechnet hat. Go kommt vergleichsweise glimpflich davon, und es lohnt sich, den Grund dafür zu verstehen, denn er erklärt auch, was die Verifizierung in Go beweisen kann und was nicht.
Warum Go-Modul-Archive exakt verifiziert werden können
Eine ZIP-Datei mit einem Go-Modul enthält den Quellcode. Dabei wird nichts kompiliert, und die Struktur des Archivs folgt einem dokumentierten Algorithmus und nicht dem, was das Paketierungsskript eines Anbieters gerade an diesem Tag zufällig tut.
Das hat eine Konsequenz, die die meisten Menschen übersehen. „go“ berechnet den Modul-Hash anhand der Dateinamen und der Dateiinhalte im Archiv. Die ZIP-Kodierung, die Komprimierungsmethode, die Änderungszeitpunkte der einzelnen Dateien und andere Metadaten werden dabei vollständig ignoriert. Daher kann jeder, der Zugriff auf den Versionsverlauf hat, das Modul neu erstellen und dieselbe h1:-Prüfsumme erhalten, selbst wenn sich die beiden ZIP-Dateien Byte für Byte unterscheiden.
Andere Ökosysteme weisen mehr bewegliche Teile zwischen einem Repository und einem veröffentlichten Artefakt auf. Maven liefert kompilierte JARs aus. Python-Wheels sind Build-Ergebnisse. Ein npm-Tarball kann aus reinem Quellcode bestehen oder aus dem, was ein prepack-Skript hinterlassen hat. Bei einigen dieser Fälle wurden im Bereich der reproduzierbaren Builds echte Fortschritte erzielt, sodass es hier keine klare Trennlinie zwischen „unmöglich“ und „exakt“ gibt. Es ist vielmehr so, dass die Prüfsumme von Go von Anfang an so konzipiert wurde, dass sie „Verpackungsrauschen“ ignoriert, was die Überprüfung der unabhängigen Rekonstruktion ungewöhnlich einfach macht.
Was sich bei den Anbietern unterscheidet, ist die Frage, ob tatsächlich jemand diesen Vergleich auf Registerebene durchführt – und zwar bei jedem Modul und bei jeder Gelegenheit. Ein Screening-Register kann den VCS-Verlauf für einen Modulpfad abrufen, das Archiv gemäß der Spezifikation erstellen und es mit dem vergleichen, was der öffentliche Proxy bereitgestellt hat. Eine Abweichung bedeutet, dass das Archiv nicht der Quelle entspricht, aus der es angeblich stammt.
Diese Unterscheidung ist von größerer Bedeutung, als es zunächst den Anschein hat. Eine exakte Rekonstruktion zeigt, dass ein Archiv mit der angegebenen Quelle übereinstimmt. Sie sagt jedoch nichts darüber aus, ob die Quelle selbst sicher ist. PolinRider ist ein typisches Beispiel dafür, da die Angreifer die legitimen Repositories direkt verändert haben und in einigen Fällen bestehende Commits zwangsweise überschrieben haben. Ein originalgetreuer Neuaufbau aus dieser Quelle reproduziert den schädlichen Inhalt ebenso originalgetreu. Die Rekonstruktion deckt Manipulationen zwischen dem Repo und dem Archiv auf. Das Aufspüren von fehlerhaftem Code innerhalb des Repos ist eine separate Aufgabe.
Hinweis: Bei Artefakten, die kompiliert werden müssen, bei Paketierungsskripten oder generierten Dateien bedeutet „aus dem Quellcode neu erstellt“ auch, dass diese Build-Bedingungen reproduziert werden. Die Prüfsumme von Go stammt direkt aus dem gepackten Quellcode-Baum, was den Vergleich ungewöhnlich einfach zu überprüfen macht. Bitten Sie einen Anbieter, Ihnen eine Abweichung zu zeigen – und nicht, eine zu beschreiben.
Warum go.sum weiterhin funktioniert
Wenn eine Registry Modul-Archive neu erstellt, ändern sich dann die Hashes, und funktioniert dann kein „go.sum“ mehr in der Organisation?
Nein. Da der Hash die gesamte Dateistruktur abdeckt und Details zur Paketierung außer Acht lässt, ergibt ein korrekt rekonstruiertes Archiv denselben Hash-Wert, den der öffentliche Proxy erzeugt hätte. Ihre vorhandenen „go.sum“-Einträge werden anhand dieses Werts validiert, und die Prüfsummen-Datenbank unter sum.golang.org stimmt weiterhin damit überein.
Aus diesem Grund sind für die Umstellung keine Änderungen an „go.mod“ oder „go.sum“ erforderlich. Es handelt sich nicht um einen Migrationspfad, der zufällig kurz ist. Es gibt nichts zu migrieren. Übereinstimmende Hashes sind das erwartete Ergebnis, und eine Abweichung ist eher ein Signal als ein Ärgernis.
Ein Fall durchbricht diese Symmetrie und verdient eine klare Antwort statt einer Fußnote. Go behandelt einen Modulpfad und eine Version gemeinsam als unveränderlich. Wenn also eine Registry gepatchte Inhalte für eine Version bereitstellt, die im Upstream bereits existiert, können diese Inhalte die Upstream-Prüfsumme nicht wiederverwenden. Ein bestehender „go.sum“-Eintrag würde die geänderten Bytes sofort ablehnen, und die öffentliche Prüfsummen-Datenbank würde weiterhin den Upstream-Hash enthalten. Gepatchte Module benötigen daher einen eigenen, dokumentierten Bereitstellungsmechanismus, sei es eine eigene Version, ein eigener Modulpfad oder eine andere kontrollierte Vertrauenskonfiguration. Wenn das Patchen nach dem EOL ein Grund für Ihren Wechsel ist, klären Sie diesen Mechanismus mit TuxCare ab, bevor Sie die Einführung planen. Dies ist der einzige Punkt, an dem die Aussage „Es ändert sich nichts“ nicht mehr zutrifft.
Die eine Zeile
GOPROXY akzeptiert jede URL, die das Modul-Proxy-Protokoll implementiert, sodass die Weiterleitung auf eine gefilterte Registrierungsstelle lediglich eine Änderung der Umgebungsvariablen erfordert.
go env -w GOPROXY=<your SecureChain Go proxy URL>,direct
Verwenden Sie vor „direct“ ein Komma statt eines Pipe-Zeichens und machen Sie sich klar, was Ihnen die jeweilige Option tatsächlich bringt. Bei Verwendung eines Kommas greift Go erst nach einem 404- oder 410-Fehler auf den nächsten Eintrag zurück. Bei Verwendung eines Pipe-Zeichens erfolgt der Rückgriff bereits nach jedem Fehler, einschließlich eines Timeouts. Ein Ausfall der Registry leitet Ihren Build also stillschweigend um dasjenige Element herum, für das Sie die Registry ursprünglich installiert haben. In beiden Fällen bedeutet „direct“, dass direkt aus der Versionskontrollquelle abgerufen wird, und ein Komma lässt bei einem 404-Fehler den Zugriff weiterhin zu. Wenn die Registry eher als Filter denn als Vorschlag dienen soll, sollten blockierte Module einen anderen Status als „nicht gefunden“ zurückgeben. Go selbst verweist genau zu diesem Zweck auf den 403-Fehler.
Dies funktioniert unabhängig davon, ob GOPROXY auf SecureChain verweist oder auf einen Repository-Manager wie Artifactory oder Nexus, der seinerseits auf SecureChain verweist. In beiden Fällen gelten dieselben Module und derselbe Arbeitsablauf.
Für CI sollte man dies in der Umgebung konfigurieren, anstatt es in ein Image einzubinden.
export GOPROXY=<your SecureChain Go proxy URL>,direct
export GOSUMDB=sum.golang.org
Dass GOSUMDB explizit aktiviert bleibt, ist beabsichtigt. Die Prüfsummenüberprüfung und die Registrierungsüberprüfung dienen unterschiedlichen Zwecken, und der Wechsel der Proxys ist kein Grund, eine der beiden Funktionen zu deaktivieren.
Profi-Tipp: Setzen Sie GOPROXY auf Entwicklerrechnern mit `go env -w` und auf Build-Agenten über CI-Umgebungsvariablen. Führen Sie anschließend auf einem tatsächlichen Runner `go env GOPROXY` aus, um zu überprüfen, was tatsächlich gesetzt ist. Basis-Images enthalten manchmal einen fest eingebetteten eigenen Wert, und genau das ist in der Regel der Grund für Probleme bei diesen Rollouts.
Was bleibt gleich und was ändert sich?
| Artikel | Änderungen |
| go.mod | Nein |
| go.sum für Upstream-Module, die unverändert bereitgestellt werden | Nein |
| Los, kompiliere, los, teste, los, hol dir | Nein |
| Anbieterverzeichnisse | Nein |
| Verhalten bei der Versionsauswahl | Nein |
| Woher die Archive abgerufen werden | Ja |
| Ob Archive vor der Auflösung geprüft werden | Ja |
An Ihren Build-Befehlen ändert sich nichts, und auch im Repository ändert sich nichts. Was sich ändert, ist die Herkunft des Archivs und ob es überprüft wird, bevor es in Ihren Build gelangt. Ein kleiner Vorbehalt bezüglich dieser Zeile mit „vendored“ ist jedoch anzumerken: Ein „vendored“-Build liest aus dem Verzeichnis „vendor/“ und fragt den Proxy überhaupt nicht ab, sodass er von der Umstellung erst dann profitiert, wenn Sie das Verzeichnis aktualisieren.
Was das Screening vor der Auflösung beiträgt
Go verfügt über keinen Hook zur Installationszeit, der den Lifecycle-Skripten von npm entspricht, was normalerweise ein Vorteil ist. Das bedeutet jedoch nicht, dass der Inhalt eines Moduls harmlos ist. Bösartiger Quellcode wird dennoch in Ihre Binärdatei kompiliert, und die Tools rund um ein Repository können eigene Ausführungswege eröffnen. PolinRider ist ein gutes Beispiel für den zweiten Fall. Bei den Payloads handelte es sich um verschleierte JavaScript-Loader, die in Projekt-Assets versteckt waren, darunter gefälschte .woff2-Schriftartdateien, und nicht um Code, der über eine Go-Init-Funktion ausgeführt wurde.
Damit ist die Überprüfung vor der Auflösung eine der frühesten automatisierten Möglichkeiten, schädliche Inhalte zu stoppen, bevor sie die Build-Umgebung erreichen.
Es gibt drei Varianten des Problems, die jeweils drei unterschiedliche Lösungen erfordern.
Ein durch „Repo-Jacking“ manipulierter Modulpfad kann eine neue, schädliche Version über den legitimen Pfad bereitstellen, ohne die von Go bereits durchgeführten Prüfsummenprüfungen zu umgehen, da diese den Inhalt des Moduls authentifizieren und nicht die Eigentumsverhältnisse oder Absichten des Repositorys. Ein Neukompilieren aus dieser kompromittierten VCS-Quelle hilft ebenfalls nicht, da das Repository nun dem Angreifer gehört. Die Überprüfung des Inhalts auf Malware vor der Auflösung ist hingegen wirksam.
Ein Beispiel für eine Version, die nach einer Kontokompromittierung upstream veröffentlicht wurde, ist der Fall PolinRider. go.sum und die Prüfsummen-Datenbank können diese Version erfolgreich authentifizieren, da sie lediglich prüfen, ob es sich um dieselben Bytes handelt, und nicht, ob diese Bytes sicher sind. Durch die Überprüfung wird diese Lücke geschlossen.
Ein vernachlässigtes Modul, das eine CVE enthält, ist ein ganz anderes Problem. Es ist nichts Schädliches eingedrungen. Der Betreuer hat lediglich aufgehört, bereits vorhandene Fehler zu beheben. In Sicherheitshinweisen wird darauf hingewiesen, aber das Schließen des Moduls bedeutet, dass es auch dann noch gepatcht wird, wenn sein Autor das Projekt verlassen hat – das ist eher Wartung als Überprüfung. Genau das deckt der „Endless Lifecycle Support“ (ELS) ab.
Das Ausmaß dieses Falls von Kontoübernahme ist bemerkenswert. Forscher fanden Spuren einer Kompromittierung in 80 Go-Modulen in 108 verschiedenen Paketen , die im Rahmen der Kampagne getroffen wurden, wobei insgesamt 162 bösartige Release-Artefakte identifiziert wurden. Die Aktivitäten wurden im Rahmen von „Contagious Interview“, auch bekannt als „Famous Chollima“, nachverfolgt. Diese Module wurden über Konten kompromittiert, die bereits seit Jahren legitim genutzt wurden, und nicht über neu registrierte Konten mit ähnlichen Namen – genau das kann eine Integritätsprüfung allein nicht aufdecken. Eine solche neue Version besteht die erste Überprüfung, da der Hash jeden mit dieser Version verbundenen Inhalt zuverlässig authentifiziert und ein Push von einem seit langem vertrauenswürdigen Betreuer auf den ersten Blick nicht verdächtig erscheint.
Gerade für Go ergibt sich hier ein unangenehmes Problem. Da Go-Module in der Regel direkt aus VCS-Tags oder Commits bezogen und nicht separat in eine Registry hochgeladen werden, kann sich ein Kompromittierung eines Repositorys auf das gesamte Modul-Ökosystem ausbreiten, ohne dass der Angreifer einen zweiten Satz von Anmeldedaten benötigt. Die Forscher stellten fest, dass das kompromittierte Konto eines Betreuers keine böswilligen Veröffentlichungen in einem Ökosystem aufwies, das einen separaten Upload-Schritt erfordert – was bedeuten könnte, dass die Angreifer nie so weit gekommen sind.
Verlassenheit ist die stillere Form derselben Erfahrung. Eine aktuelle Analyse von 13,1 Millionen Open-Source-Paketen ergab, dass der Anteil der „Out-of-Band“-Pakete bei Go – gewichtet nach abhängigen Repositories statt nach der Anzahl der Pakete – zwischen 33,2 % und 57,9 % liegt. Die Streuung hängt von der Definition ab – der obere Wert umfasst alles, wofür seit 730 Tagen kein Release mehr veröffentlicht wurde. Der untere Wert setzt zudem voraus, dass in diesem Zeitraum keine Repository-Commits stattgefunden haben. So oder so treffen die genannten Go-Beispiele genau ins Schwarze: „gopkg.in/yaml.v2“, „jwt-go“, „AWS SDK for Go v1“. Keine Registry-Architektur, ob geprüft oder nicht, kann dieses Problem allein lösen. Es erfordert kontinuierliche Patches – und genau dafür ist der dritte oben genannte Fall gedacht.
Einführung ohne Unterbrechung der Builds
Vier Phasen, wobei die Reihenfolge wichtiger ist als die Geschwindigkeit.
| Phase | Aktion | Was Sie lernen |
| 1 | GOPROXY für einen nicht kritischen Dienst aktivieren | Ob die Auflösung eines Modulpfads fehlschlägt |
| 2 | Abhängigkeiten aus einem leeren Modul-Cache herunterladen und überprüfen | Ob sich Module, die über die neue Registry bereitgestellt werden, anhand Ihrer bestehenden go.sum authentifizieren |
| 3 | CI in allen Repositories einführen | In welchen Pipelines war GOPROXY fest in einem Image hinterlegt? |
| 4 | Den ausgehenden Datenverkehr des Build-Agenten auf die Registry und die Prüfsummen-Datenbank beschränken | Was wurde bei der Konfiguration stillschweigend umgangen? |
In Phase zwei werden die Belege vorgelegt, nach denen ein skeptischer Gutachter tatsächlich fragen wird.
go clean -modcache
Go Mod herunterladen
go mod verify
Es lohnt sich, genau zu erklären, was die einzelnen Befehle bewirken. Bei leerem Cache zwingt „go mod download“ die erforderlichen Module über die neue Registrierung und authentifiziert sie anhand Ihrer festgeschriebenen „go.sum“-Einträge oder anhand der konfigurierten Prüfsummen-Datenbank, sofern dort noch kein Hash-Wert gespeichert ist. „go mod verify“ bestätigt anschließend, dass sich die zwischengespeicherten Inhalte seit dem Herunterladen nicht verändert haben. Führen Sie anschließend Ihren normalen Build- oder Testlauf durch, und die Kompatibilitätsangabe wird anhand der aktuellen Abhängigkeiten Ihres Projekts in Ihrer eigenen Umgebung und nicht anhand einer Anbieter-Sammlung validiert.
In Phase vier wird die Richtlinie in die Praxis umgesetzt. Solange der Ausgang nicht gesperrt ist, ist GOPROXY lediglich eine Empfehlung, die jeder außer Kraft setzen kann, um eine Freitagsbereitstellung freizugeben. Das bloße Blockieren von proxy.golang.org reicht nicht aus, da dieser abschließende direkte Verweis stattdessen 404-Fehler an GitHub und andere weiterleitet. Setzen Sie die Registry auf die Whitelist und blockieren Sie den Rest. Eine Überprüfung vor dem Umschalten der Regel: Die Prüfsummenüberprüfung benötigt weiterhin Zugriff auf die Prüfsummen-Datenbank, entweder direkt oder über einen Proxy, der diese spiegelt. Stellen Sie daher sicher, dass diese Abfragen weiterhin funktionieren, anstatt dies erst bei der ersten fehlerhaften Pipeline festzustellen.
Profi-Tipp: Führen Sie Phase vier in der Staging-Umgebung lange genug durch, um Ihre normalen Build-Workflows vor der Produktion zu testen. So wird deutlich, welche Pipelines tatsächlich direkt und unbemerkt funktionierten – und diese Übersicht ist jetzt als Liste weitaus besser als später als Störung.
Sichern Sie Ihre Go-Lieferkette ab
Wenn die Phasen eins und zwei in Ihren eigenen Repositories bereits abgeschlossen sind – gemessen an Ihrem eigenen go.sum –, dann ist dies der Kompatibilitätsnachweis, den eine Sicherheitsüberprüfung benötigt, und Sie haben ihn selbst erstellt. Was SecureChain für Go dazu bietet, ist eine kontinuierliche Überprüfung bei jedem Abruf anstelle einer einmaligen Prüfung sowie die Bereitstellung von Patches, die auch dann fortgesetzt wird, wenn der Betreuer eines Moduls nicht mehr aktiv ist – und zwar über ein Registry, das dasselbe Modul-Proxy-Protokoll verwendet, das Ihre Toolchain bereits erwartet. Bevor Sie sich auf die Patches nach Ablauf der Lebensdauer (EOL) verlassen, sollten Sie den dokumentierten Versions- und Prüfsummenmechanismus für gepatchte Go-Module überprüfen, damit dieser in die Bereitstellung integriert werden kann.
Angebot anfordern für SecureChain an oder erfahren Sie, wie sich SecureChain im Vergleich zu Chainguard schlägt.
FAQ
Wie ändere ich meinen Go-Modul-Proxy?
Setzen Sie die Umgebungsvariable GOPROXY auf die Registrierungs-URL, wobei Sie vor „direct“ ein Komma anstelle eines Pipe-Zeichens verwenden. Mit dem Befehl „go env -w GOPROXY=…“ wird die Variable auf einem Entwicklerrechner dauerhaft gespeichert. In CI sollten Sie die Variable in der Umgebung und nicht im Basis-Image festlegen.
Führt das Wechseln der Go-Modul-Proxys zu einem Ausfall von go.sum?
Nein, vorausgesetzt, die Registry stellt denselben Modulinhalt bereit. Der Modul-Hash in Go wird anhand von Dateinamen und Dateiinhalten ermittelt und nicht anhand von Details der ZIP-Kodierung. Daher ergeben unabhängig voneinander erstellte Archive mit derselben Dateistruktur denselben Hash. Modifizierte Module bilden hier eine Ausnahme, da unterschiedliche Inhalte per Definition einen unterschiedlichen Hash ergeben. Wie dieser Inhalt versioniert und authentifiziert wird, hängt vom Bereitstellungsmechanismus der Registry für modifizierte Module ab.
Kann ich die Prüfsummen-Datenbank aktiviert lassen?
Ja, und das sollten Sie auch tun. Die GOSUMDB-Überprüfung und das Registry-Screening dienen der Klärung unterschiedlicher Fragen, und bei Upstream-Modulen, die unverändert bereitgestellt werden, stimmen die Hashes konstruktionsbedingt überein. Lassen Sie GOSUMDB=sum.golang.org für diese Module aktiviert und behandeln Sie gepatchte Module gemäß dem Versions- und Prüfsummenmechanismus, den Ihre Registry für diese Module dokumentiert.
Muss ich die Datei „go.mod“ ändern, um einen anderen Proxy zu verwenden?
Nein. go.mod speichert Modulpfade und -versionen, und abgesehen von eventuell von Ihnen festgelegten „replace“-Anweisungen hat es keinen Einfluss darauf, woher Archive abgerufen werden. Die Proxy-Auswahl erfolgt über die Umgebungskonfiguration.
Wie kann ich die Kompatibilitätsangabe selbst überprüfen?
Leeren Sie den Modul-Cache mit dem Befehl „go clean -modcache“, führen Sie „go mod download“ über die neue Registry aus, damit Go alle Daten erneut abruft und anhand Ihrer vorhandenen Prüfsummen authentifiziert, und führen Sie anschließend „go mod verify“ gefolgt von Ihrem üblichen Build oder Ihrer Testsuite aus. Ein erfolgreicher Durchlauf bedeutet, dass die erhaltenen Module mit den Hashes übereinstimmen, denen Ihr Projekt bereits vertraut hat.



