
Finden Sie Anmeldedaten in Screenshots, speichern Sie sie in Ihrem Secret Manager und schwärzen Sie sie unwiderruflich aus dem Bild — lokal, offline, OCR-basiert.
Finde Anmeldedaten in Screenshots, extrahiere sie in einen Secret Manager und entferne sie irreversibel aus den Bildern — damit Geheimnisse nicht in deinen Notizen, Screenshots und ~/Desktop verrotten.
Lokal. Offline. Leise. Standardmäßig kein Netzwerk, keine Telemetrie.
screenscrub verbindet zwei bestehende Werkzeugkategorien: GUI-Redakteure (Xnapper, Shhshot, macshot) verwischen PII von Hand, können aber ein Geheimnis nicht von einer Adresse unterscheiden oder erfassen, was sie verbergen; Secret-Scanner (gitleaks, TruffleHog) finden echte Anmeldedaten, aber nur in Text, nie in einer PNG. screenscrub bringt gitleaks-würdige Erkennung — plus ein Red-Team-Paket und Entropieanalyse — zu Pixeln, kopflos: es erfasst jedes Geheimnis in deinem Manager, entfernt das Bild irreversibel und führt eine erneute OCR des Ergebnisses durch, um zu beweisen, dass das Geheimnis weg ist.
Ein Sicherheitsnetz, keine Garantie — screenscrub behauptet nie, dass ein Bild „garantiert sauber“ ist; OCR und Erkennung übersehen beide Dinge, also überprüfe die Ergebnisse immer selbst. Lies dies, bevor du dich darauf verlässt.
screenscrub scan ~/Screenshots # Trockenlauf: erkennen + melden, nichts schreiben
screenscrub clean ~/Screenshots --out ~/clean \ # extrahieren, schwärzen, verifizieren, quarantänisieren
--sink file://./secrets.age --yes
screenscrub verify ~/clean # beweisen, dass ein Ordner sauber ist (exit≠0 falls nicht)
screenscrub clean --keep-originals ./tmp
Cleaning 7 image(s) in ./tmp (7 worker(s))…
[1/7] tmp/ssh.jpg — 6 region(s) → tmp/ssh.redacted.jpg ✓ verified
[2/7] tmp/key.jpg — 13 region(s) → tmp/key.redacted.jpg ✓ verified
[3/7] tmp/test2.jpg — 12 region(s) → tmp/test2.redacted.jpg ✓ verified
[4/7] tmp/test5.jpg — 13 region(s) → tmp/test5.redacted.jpg ✓ verified
[5/7] tmp/test3.jpg — error: verification failed: 4 secret region(s) still detectable in tmp/test3.redacted.jpg; original preserved
[6/7] tmp/test4.jpg — error: verification failed: 9 secret region(s) still detectable in tmp/test4.redacted.jpg; original preserved
[7/7] tmp/test6.jpg — error: verification failed: 7 secret region(s) still detectable in tmp/test6.redacted.jpg; original preserved
7/7 file(s) flagged, 382 region(s) total, 3 file(s) errored/unverified.
By kind:
high-entropy 343
keyword-secret 15
db-connection-uri 10
github-pat 6
unix-crypt-hash 6
aws-access-key 1
stripe-key 1
Needs manual attention (3):
tmp/test3.jpg — error: verification failed: 4 secret region(s) still detectable in tmp/test3.redacted.jpg; original preserved
tmp/test4.jpg — error: verification failed: 9 secret region(s) still detectable in tmp/test4.redacted.jpg; original preserved
tmp/test6.jpg — error: verification failed: 7 secret region(s) still detectable in tmp/test6.redacted.jpg; original preserved
| Vorher — Geheimniswerte sichtbar | Nach clean — irreversibel geschwärzt |
![]() |
Derselbe Screenshot vor und nach clean: jeder Geheimniswert wird in Pixel dekodiert, eingekastet und in ein neues Bild (irreversibel) neu kodiert — Labels und Struktur bleiben lesbar.
Erfordert die tesseract-OCR-Binärdatei im PATH:
brew install tesseractwinget install UB-Mannheim.TesseractOCR (oder der UB-Mannheim-Installer)apt-get install tesseract-ocrDann bauen:
go build -o screenscrub ./cmd/screenscrub
Cross-Kompilierung nach macOS (arm64/amd64) und Windows (amd64) — es greift auf tesseract zu, anstatt cgo zu verwenden. Nur auf macOS getestet.
scan <Verzeichnis|Datei> — TrockenlaufErkennt und meldet; schreibt nichts.
screenscrub scan ~/Screenshots --ignore 'node_modules/**' --ignore '*.thumb.png'
screenscrub scan shot.png --json # maschinenlesbarer Bericht
screenscrub scan ~/Screenshots --preview ~/review # überprüfen, was clean schwärzen würde
--preview <Verzeichnis> schreibt eine nicht-destruktive Kopie jedes markierten Bildes, bei der jeder erkannte Bereich umrandet (nicht ausgefüllt) ist, damit du vor dem Ausführen bestätigen kannst, was clean schwärzen würde. ⚠️ Diese Kopien enthalten noch die Geheimnisse — das Verzeichnis wird mit 0700 erstellt und darf nicht geteilt werden.
Der Bericht endet mit einer Zusammenfassung: einer Aufschlüsselung nach Art und einer expliziten Liste „Benötigt manuelle Aufmerksamkeit“ — Dateien, die fehlgeschlagen sind, die Verifikation nicht bestanden haben oder keinen OCR-Text bei einem vermeintlichen Screenshot erzeugt haben (ein stiller OCR-Fehler wird als sauber gelesen, also wird er angezeigt, statt ihm zu vertrauen).
scan --fail-on-findings beendet sich mit einem Fehler, wenn etwas erkannt wird — ein Pre-Commit/CI-Gate.
clean <Verzeichnis|Datei> — extrahieren, schwärzen, quarantänisierenSCREENSCRUB_PASSPHRASE=… screenscrub clean ~/Screenshots \
--out ~/Screenshots/clean \
--sink file://./secrets.age \
--yes
Für jedes Bild mit Funden führt clean Folgendes aus:
<Name>.redacted.png nach --out (oder neben die Quelle),<out>/quarantine/, verschlüsselt mit age.Geheimnisse gehen an den Sink, den du mit --sink angibst: age-Datei (Standard), 1Password (op://), KeePassXC (keepassxc://), macOS-Schlüsselbund (keychain://) oder HashiCorp Vault (vault://) — oder hardwaregestützte age-Empfänger (YubiKey, Touch ID). Siehe Secret Sinks.
Flags:
--exclude-kind und --min-confidence sind lokale (kein Netzwerk) Präzisionsknöpfe für ein verrauschtes Korpus — das Offline-Gegenstück zu --llm. Sie tauschen Rückruf gegen einen leiseren Bericht, verwende sie daher bewusst. Beide funktionieren auch bei scan/verify und können in --config gesetzt werden (exclude_kinds, min_confidence).
Reihenfolge der Passphrase-Auflösung: --passphrase, dann die Konfigurationsdatei, dann SCREENSCRUB_PASSPHRASE. Vermeide --passphrase in der Befehlszeile — argv ist für andere Prozesse sichtbar.
verify <Verzeichnis|Datei> — beweisen, dass ein Ordner sauber istFührt eine erneute OCR jedes Bildes durch, führt die Erkennung erneut aus und beendet sich mit einem Fehler, wenn noch eine Geheimnisregion gefunden wird — verwende es als Liefer-/CI-Gate, bevor du Screenshots an einen Kunden sendest. (Es beweist, dass OCR das Geheimnis nicht lesen kann, nicht dass ein Mensch es nie könnte.)
screenscrub verify ~/deliverable/screenshots
echo $? # 0 = sauber, ungleich Null = ein Geheimnis ist noch erkennbar
clean führt dieselbe Prüfung automatisch für jede geschwärzte Kopie durch und quarantänisiert oder schreddert kein Original, dessen geschwärzte Kopie fehlschlägt; --no-verify überspringt sie (nicht empfohlen).
open <Speicher> — Geheimnisse oder ein quarantänisiertes Original wiederherstellenHole deine Daten zurück: open entschlüsselt den age-Sink (die gespeicherten Geheimnisaufzeichnungen) oder ein quarantänisiertes Original nach --out, niemals nach stdout. Siehe Entschlüsseln von Speichern.
--llm — harmlose Übermarkierungen mit einem LLM entfernengitleaks-würdige Regeln über OCR-Text (mit OCR-Rauschen) führen unweigerlich zu Übermarkierungen: der rückruf-orientierte Detektor zeigt harmlose hochentropische Strings an, die ein Operator behalten möchte — Hostnamen, GUIDs, git-SHAs, NTLM-Hashes, die selbst der Kompromittierungsnachweis sind. --llm lässt jeden Kandidaten von Claude (Opus 4.8) prüfen, echte Geheimnisse werden behalten, harmlose Identifikatoren verworfen; durch LLM bestätigte Regionen werden rot gefüllt.
ANTHROPIC_API_KEY=… screenscrub clean ~/Screenshots --out ~/clean --llm --yes
Dies bricht absichtlich mit lokal-und-leise: es sendet die Kandidaten-Strings (die erkannten Geheimnisse) an die Anthropic-API, daher ist es nur opt-in, gibt eine Warnung aus und benötigt einen API-Schlüssel. Es schlägt geschlossen fehl: Jeder API-/Netzwerkfehler behält alle Funde (schwärzt alles), anstatt das Risiko einzugehen, ein echtes Geheimnis zu verlieren. Es macht einen API-Aufruf pro markiertem Bild (maximal 4 gleichzeitig, unabhängig von --jobs) — beachte die Ratenbegrenzung und Kosten bei großen Verzeichnissen.
--watchscreenscrub clean ~/Screenshots --watch --sink file://./secrets.age --yes
Verarbeitet alles bereits Vorhandene, überwacht dann auf neue/geänderte Bilder und schrubbt jedes, sobald es erscheint. Ausgaben *.redacted.png werden ignoriert, um Endlosschleifen zu vermeiden.
Über OCR-Token kombiniert screenscrub:
AKIA…, GitHub ghp_…, GitLab, Slack, Stripe, OpenAI, GCP-API-Schlüssel, JWTs und PEM-Kopfzeilen. (Kopiert, nicht importiert, um klein und vollständig offline zu bleiben.)postgres://u:p@…), HTTP-Basic/Bearer-Auth-Header, NetNTLMv2- und NTLM- (pwdump-) Hashes, /etc/shadow-crypt-Hashes, PuTTY- und OpenSSH-Private-Keys, SendGrid/npm-Tokens.password, token=, secret, api_key, …), die den benachbarten Wert markieren, selbst wenn er keinem Muster entspricht und niedrige Entropie hat.BEGIN/END-Markierungen und schwärzt großzügig die gesamte umschließende Region, anstatt auf wortweise Treffer zu vertrauen.Jeder Treffer wird zurück auf die Pixelkästen der Token abgebildet, die ihn ausmachen (zwei Zeilenrekonstruktionen — mit und ohne Abstand — stellen Geheimnisse wieder her, die OCR aufgrund von Leerzeichen geteilt hat), und die Kästen werden vor dem Füllen gepolstert.
Ein Sink ist eine Methode: Store(Secret) error. Mitgelieferte Adapter:
file:// — age-verschlüsselte lokale Datei (Standard). Keine externen Abhängigkeiten; ein JSON-Array von Datensätzen, verschlüsselt mit einem age-scrypt-Passwort (oder an age-Empfänger — siehe hardwaregestützte Verschlüsselung unten).op:// — 1Password CLI. Führt op item create mit dem Wert auf stdin aus (niemals in argv).keepassxc://./vault.kdbx — KeePassXC. Beliebter plattformübergreifender lokaler KeePass-Manager. Führt keepassxc-cli add aus; das Datenbank-Passwort und das Geheimnis werden beide auf stdin übergeben (niemals in argv). Das Datenbank-Passwort ist die aufgelöste Passphrase (--config/SCREENSCRUB_PASSPHRASE).keychain://screenscrub — macOS-Schlüsselbund. Führt security add-generic-password aus. Hinweis: Das security-Tool akzeptiert das Geheimnis nur als Befehlszeilenargument, daher ist es kurzzeitig für ps desselben Benutzers sichtbar (macOS verbirgt argv vor anderen Benutzern). Für strengere Hygiene bevorzuge 1Password, KeePassXC oder den Secure-Enclave-Empfänger unten.Um einen eigenen hinzuzufügen, implementiere sink.SecretSink (internal/sink) und verkable es in sink.FromURI. Das ist der gesamte Vertrag.
Der standardmäßige age-Datei-Sink und die Quarantäne können an age-Empfänger statt an ein Passwort verschlüsselt werden, auch an hardwaregestützte über age-Plugins:
# YubiKey (PIV) — installiere age-plugin-yubikey, dann:
screenscrub clean ~/Screenshots --out ~/clean \
--sink file://./secrets.age \
--recipient age1yubikey1q... --yes
# Apple Secure Enclave / Touch ID — installiere age-plugin-se, dann:
screenscrub clean ~/Screenshots --out ~/clean \
--recipient age1se1q... --yes
# Einfaches age-Schlüsselpaar oder mehrere Empfänger / eine Empfängerdatei:
screenscrub clean ~/Screenshots --recipient age1abc... --recipients-file team.age.pub --yes
Im Empfängermodus wird keine Passphrase benötigt; sowohl der Sink als auch die verschlüsselte Quarantäne gehen an die Empfänger. Wiederherstellung mit dem Hardware-Token: age -d -i <Identität> secrets.age (die Entschlüsselung fordert zur YubiKey-Berührung / Touch ID auf). Die Verschlüsselung an einen Plugin-Empfänger benötigt die Binärdatei age-plugin-<Name>; die Entschlüsselung benötigt zusätzlich das Gerät.
openDer Sink und die Quarantäne verwenden separate Schlüssel, die aus deiner einen Passphrase abgeleitet werden (HKDF), sodass das Knacken eines Speichers den anderen nicht öffnen kann. Da die Schlüssel auf der Festplatte abgeleitet sind, entschlüssle sie mit screenscrub statt mit rohem age:
screenscrub open ./secrets.age --out secrets.json # die Geheimnisaufzeichnungen
screenscrub open ~/clean/quarantine/shot.png.ab12cd34.age --out shot.png # ein Original
open versucht jeden abgeleiteten Schlüssel automatisch und schreibt den Klartext nach --out (niemals stdout). Für Speicher im Empfängermodus übergibst du eine age-Schlüsseldatei: screenscrub open secrets.<id>.age --identity key.txt --out secrets.json (für YubiKey/Touch ID verwende age -d -i direkt, was das Hardware-Plugin antreibt). Der Empfängermodus schreibt eine Datei pro Geheimnis (secrets.<hash>-<rand>.age), sodass wiederholte Läufe sich nie überschreiben.
go test ./... # Unit-Tests laufen ohne tesseract; OCR/Neu-OCR-Tests werden übersprungen, wenn es fehlt
Die Hauptgarantie wird durch einen End-to-End-Test abgedeckt: einen Screenshot mit einem AWS-Schlüssel rendern, die echte OCR → Erkennung → Schwärzungspipeline ausführen, die Ausgabe neu OCRen und behaupten, dass das Geheimnis weg ist (internal/redact).
screenscrub ist keine Lizenz, aufzuhören nachzudenken.
password:-Zeilen); ein Geheimnis in einer Form, die sie nicht erkennt, wird durchgelassen.Sie ist auf Rückruf gegenüber Präzision getunt — sie übermarkiert absichtlich, denn eine Anmeldedaten in einem Bild ist der katastrophale Fall, und ein falsch Positiver kostet dich nur einen geschwärzten Klecks.
Du kannst einen realistischen Anwendungsfall im Ordner testdata/ sehen, der aus Screenshots von RExpository stammt:
https://jaimepolop.github.io/RExpository/
Es ist nicht perfekt, aber ziemlich gut.
clean eine erneute OCR durch und führt die Erkennung erneut aus; falls ein Geheimnis immer noch erkennbar ist, weigert es sich, das Original zu quarantänisieren oder zu zerstören und markiert die Datei. Schwärzungsboxen werden proportional zur Glyphenhöhe aufgepolstert, sodass Anti-Alias-Kanten bei großen/hochauflösenden Texten abgedeckt werden.clean schreibt die geschwärzte Kopie, verifiziert sie und verschiebt dann das ungeschwärzte Original in eine mit age verschlüsselte Quarantäne und entfernt es von seinem ursprünglichen Speicherort — erst, nachdem die Kopie als sauber verifiziert und die extrahierten Geheimnisse sicher auf der Festplatte sind. Destruktive Schritte erfordern --yes.AK****…**LE). Die einzige Klartextkopie lebt im Arbeitsspeicher, bis sie deinen verschlüsselten Sink erreicht.--purge und die Grenzen des sicheren LöschensStandardmäßig werden Originale (verschlüsselt) in der Quarantäne aufbewahrt, damit eine falsche Schwärzung wiederherstellbar ist. --purge schreddert stattdessen das Original: Überschreiben mit Zufall, Überschreiben mit Nullen, dann Löschen.
Sicheres Löschen ist unzuverlässig. Auf SSDs, Copy-on-Write-Dateisystemen (APFS, Btrfs, ZFS), journaled Dateisystemen und gesnapshoteten/gesicherten Volumes garantiert Überschreiben-dann-Löschen nicht, dass die ursprünglichen Bytes verschwunden sind — Wear-Leveling und Snapshots können sie behalten. Die einzige wirkliche Verteidigung ist, Klartext von vornherein nie zu persistieren. Bevorzuge die verschlüsselte Quarantäne und behandle --purge als Best-Effort.
OCR-Schnittstelle — ein möglicher zukünftiger Zusatz.Nachgebaute Anmeldedatenmuster stammen von gitleaks (MIT).
![]() |
| Flag | Bedeutung |
|---|
--out <Verzeichnis> | Wohin die geschwärzten Kopien gehen (Standard: neben der Quelle) |
--sink <uri> | file://./secrets.age · op://Vault · keepassxc://./v.kdbx · keychain://service · vault://KV |
--recipient <age1…> | An einen age-Empfänger verschlüsseln (wiederholbar): X25519, YubiKey oder Touch ID |
--recipients-file <Datei> | Datei mit age-Empfängern, einer pro Zeile |
--passphrase | Passphrase für den Datei-Sink / Quarantäne (bevorzuge die Umgebungsvariable oder --config) |
--watch | Weiterlaufen lassen; neue Screenshots verarbeiten, sobald sie eintreffen (fsnotify) |
--purge | Originale schreddern statt quarantänisieren (siehe Hinweis unten) |
--keep-originals | Nur geschwärzte Kopien schreiben; Originale am Platz lassen (keine Quarantäne, keine Passphrase, kein --yes) — gegenseitig ausschließend mit --purge |
--yes | Bestätigung für destruktive Behandlung der Originale (erforderlich) |
--config <Datei> | JSON-Konfiguration; erlaubt es, die Passphrase aus argv herauszuhalten |
--no-verify | Die erneute OCR-Verifikation der geschwärzten Ausgabe überspringen (nicht empfohlen) |
-i, --interactive | Jedes markierte Bild öffnen und vor der Bearbeitung das Schwärzen/Überspringen bestätigen |
--llm | Claude verwenden, um harmlose Übermarkierungen zu entfernen; sendet Kandidaten-Strings an die Anthropic-API |
--llm-api-key | Anthropic-API-Schlüssel für --llm (oder ANTHROPIC_API_KEY) |
--jobs N | N Bilder parallel verarbeiten (Standard: CPU-Anzahl) |
--manifest <Datei> | Eine JSON-Zuordnung von Original→geschwärzt→Regionen schreiben |
--ocr-raw / --ocr-upscale N | Vorverarbeitung von dunklen Terminals deaktivieren / vor OCR hochskalieren |
--exclude-kind <Art> | Funde einer Art unterdrücken (wiederholbar), z. B. high-entropy — Offline-Präzisionsknopf |
--min-confidence <0..1> | Funde unterhalb dieses Vertrauenswerts verwerfen — Offline-Präzisionsknopf |
--json | Den Bericht als JSON ausgeben |
--ignore <Glob> | Glob ignorieren, wiederholbar; ** trifft jede Tiefe |
--lang | Tesseract-Sprache (Standard eng) |
vault:// — HashiCorp Vault KV v2 — vorhanden, aber zurückgestellt/weniger verbreitet; der Pfad hasht das Geheimnis, sodass es nie in der URL erscheint.