Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
watermarks-remover — Eine Privacy-First-App, die KI-Wasserzeichen aus Inhalten entfernt, die dir gehören. | Kitploit
Tools/GitHubGitHub/guillaumemeyer/watermarks-remover
SteganografieDigitale ForensikPrivatsphäreDienstprogramme & FrameworksMaschinelles LernenRed TeamingKI-SicherheitAdversarial-Angriff
GitHubguillaumemeyer/watermarks-remover

watermarks-remover

Eine Privacy-First-App, die KI-Wasserzeichen aus Inhalten entfernt, die dir gehören.

Repository anzeigen
22.3k2.6k78vor 3 TagenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
root@kitploit:~
_ _ _ ____ ___ ____ ____ _  _ ____ ____ _  _ ____    ____ ____ _  _ ____ _  _ ____ ____
| | | |__|  |  |___ |__/ |\/| |__| |__/ |_/  [__  __ |__/ |___ |\/| |  | |  | |___ |__/
|_|_| |  |  |  |___ |  \ |  | |  | |  \ | \_ ___]    |  \ |___ |  | |__|  \/  |___ |  \

watermarks-remover

CI Release Stars Forks

Agent-Skill + stdlib-Python-Service zum Entfernen herstellerübergreifender KI-Herkunftskennzeichen aus Text und Dateien — für Datenschutz und Hygiene bei Inhalten, die Ihnen gehören. Das Skill ist ein dünner Client: Es steuert die Maschinerie über HTTP, sodass der Agent-Host kein Python benötigt.

Hersteller / Ökosysteme (auf Klassenebene): Claude, Gemini / SynthID-Text, OpenAI-Herkunftsoberflächen, Open-LLM-Markierungen im Kirchenbauer-Stil (Green-List) sowie Keyed-Gumbel- / EXP-Markierungen (Aaronson).

Neueste Version: v0.7.0

Skill-Pfad: skills/remove-ai-marks/
Service-Pfad: service/
(Migration: früher remove-claude-marks; Slash-Alias /remove-claude-marks weiterhin dokumentiert)

Installation (Agent-Skill)

Das Skill enthält keinen Code — es ruft den Service über HTTP auf. Installieren Sie das Skill (nur Markdown) und starten Sie den Service, legen Sie dann WATERMARKS_SERVICE_URL fest, falls dieser nicht http://127.0.0.1:8765 lautet.

In Claude Code ist der schnellste Weg der mitgelieferte Plugin-Marketplace — kein Klonen, und er aktualisiert sich direkt. Überall sonst deckt ein Installer jeden unterstützten Host ab (Python 3.10+ stdlib, keine Abhängigkeiten):```bash python3 install_skill.py --skill remove-ai-marks --target claude-code

root@kitploit:~
| Host | Ziel | Landet in |
| --- | --- | --- |
| Claude Code (persönlich) | `--target claude-code` | `~/.claude/skills/<skill>` (beachtet `CLAUDE_CONFIG_DIR`) |
| Claude Code (Projekt) | `--target claude-project --project-dir PATH` | `PATH/.claude/skills/<skill>` |
| Cowork, claude.ai, Cloud-Sessions, Routinen | `--target cowork` | `dist/<skill>.zip` zum Hochladen unter **Customize → Skills** |
| Cursor | `--target cursor` (Standard) | `~/.cursor/skills/<skill>` |

Mitgelieferte Skills: `remove-ai-marks` (vollständig, servicegestützt) und
`clean-user-facing-text` (nur Text, eigenständig). `--list` gibt sie aus.
Bestehende Installationen bleiben erhalten, sofern du nicht `--force` übergibst; der Austausch wird
zuerst vorbereitet und die vorherige Installation als eindeutig benanntes Backup aufbewahrt.
`--link` verlinkt diesen Checkout per Symlink, anstatt zu kopieren, sodass Änderungen live
übernommen werden. Unter Windows verwende `py install_skill.py ...`; der Wrapper `install-skill.sh`
ist für macOS/Linux-Shells vorgesehen.

Bevor etwas geschrieben wird, validiert der Installer den Skill gegen die
[Agent Skills](https://agentskills.io)-Packaging-Regeln, die claude.ai-Uploads
und die Skills API durchsetzen: nur spezifikationskonformes Frontmatter (`name`, `description`,
`license`, `compatibility`, `metadata`, `allowed-tools`), ein kleingeschriebener, mit Bindestrichen
verbundener `name` von höchstens 64 Zeichen, der mit dem Verzeichnis übereinstimmt, eine nicht leere
`description` von höchstens 1024 Zeichen. Das Cowork-Bundle muss zusätzlich
das Upload-Limit von 30 MB einhalten, was der Packager erzwingt.

### Automatische Bereinigung per Hook (deterministisch)

Ein Skill ist eine Anweisung: Das Modell entscheidet, ob es ihn aufruft, und das
Modell ist die Instanz, die die Markierungen erzeugt. Ein **Hook** wird von der Harness
bei jedem passenden Tool-Aufruf ausgeführt, ohne dass Kooperation erforderlich ist. Das macht den Hook zur
deterministischen Hälfte dieses Workflows.

Das Plugin registriert einen `PostToolUse`-Hook auf `Write|Edit|MultiEdit|NotebookEdit`,
der [`service/scripts/hook_written_file.py`](https://github.com/guillaumemeyer/watermarks-remover/blob/main/service/scripts/hook_written_file.py)
gegen die Datei ausführt, die der Agent gerade geschrieben hat. Zwei Modi, entsprechend der Pre-Commit-
Konvention von standardmäßiger Prüfung:

| Modus | Verhalten |
| --- | --- |
| `check` (Standard) | Meldet Herkunftsmarkierungen, lässt die Datei unverändert. Befunde gehen an das Modell (Exit 2), damit es deren Bereinigung anbieten kann. |
| `clean` | Entfernt die Markierungen direkt, und teilt dem Modell anschließend mit, dass sich die Datei auf der Festplatte geändert hat. |

Lege den Modus in den Einstellungen des Plugins fest (**Hook mode** in `/plugin manage`,
vom Hook als `CLAUDE_PLUGIN_OPTION_HOOK_MODE` gelesen), oder mit
`WATERMARKS_HOOK_MODE=clean` in der Umgebung. Der Hook-Befehl interpoliert bewusst
**nicht** `${user_config.hook_mode}`: Claude Code weigert sich, einen Hook auszuführen, der auf eine Option verweist, die der Benutzer nie über `/plugin manage` geöffnet hat, um
sie festzulegen — ein deklarierter `default` erfüllt dies nicht —, sodass eine Interpolation bedeuten würde,
dass der Hook bei einer Neuinstallation stillschweigend nie ausgeführt wird. Die Erkennung verwendet `audit_lib`s
`scan_file` / `is_actionable` wieder, sodass der Hook, das Pre-Commit-Gate und der CI-
SARIF-Export darin übereinstimmen, was als actionable gilt; die Bereinigung ruft
`clean_file.py` auf, sodass keine Bereinigungslogik dupliziert wird. Der `clean`-Modus schreibt in eine
benachbarte temporäre Datei und tauscht nur bei einem echten Unterschied aus, sodass Dateien, die
bereits sauber waren, ihre mtime behalten und keine Datei-Watcher erneut auslösen.

Ohne das Plugin binde es selbst in `~/.claude/settings.json` (oder eine Projekt-
`.claude/settings.json`) ein:```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit|NotebookEdit",
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["/path/to/watermarks-remover/service/scripts/hook_written_file.py",
                     "--mode", "check"],
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Unter Windows ersetzen Sie python3 durch py.

Was ein Hook nicht kann. Kein Hook kann die Chat-Nachricht des Assistenten umschreiben, bevor Sie sie lesen. Der Stop-Hook von Claude Code empfängt last_assistant_message schreibgeschützt, und es gibt keinen Vor-Versand-Filter für endgültige Antworten — dieselbe Einschränkung, die dieses Projekt bereits für Cursor-Regeln dokumentiert. Die deterministische Garantie deckt also Dateien ab, die der Agent schreibt, plus das Pre-Commit-Gate für alles, was auf dem Weg in Git ist. Text, der nur im Chat-Transkript existiert, hängt weiterhin vom Skill-Workflow ab, der auf Modell-Anweisungen basiert und daher Best-Effort ist.

Claude Code Plugin (Marketplace)

Das Repository ist auch ein Claude Code Plugin und ein Single-Plugin-Marketplace (.claude-plugin/), sodass beide Skills mit zwei Befehlen installiert und aktualisiert werden können, ohne Klonen oder Skript:``` /plugin marketplace add guillaumemeyer/watermarks-remover /plugin install watermarks-remover@watermarks-remover

root@kitploit:~
Die Skills werden dann mit Namespace geladen: `/watermarks-remover:remove-ai-marks` und
`/watermarks-remover:clean-user-facing-text` (das bloße `/remove-ai-marks` funktioniert ebenfalls,
wenn nichts anderes den Namen beansprucht). `/plugin marketplace update
watermarks-remover` zieht spätere Versionen. Dasselbe funktioniert über die CLI mit
`claude plugin marketplace add …` / `claude plugin install …` und aus einem lokalen
Checkout, indem ein Pfad anstelle von `owner/repo` übergeben wird.

Maintainer: `make plugin-validate` führt `claude plugin validate . --strict`
gegen beide Manifeste aus; `tests/test_plugin_manifest.py` deckt dieselben Dateien
ab, ohne dass die CLI benötigt wird.

### Claude Code```bash
# Personal — available in all your projects
python3 install_skill.py --skill remove-ai-marks --target claude-code
# or: make install-claude-code-skill

# Project — commit .claude/skills/ to share it with the repo
python3 install_skill.py --skill remove-ai-marks --target claude-project \
  --project-dir /path/to/project
# or: make install-claude-project-skill PROJECT=/path/to/project

Claude Code erkennt persönliche und projektbezogene Skills ohne Neustart; /skills listet auf, was geladen wurde. Aufrufen mit /remove-ai-marks oder darum bitten, „AI Wasserzeichen / C2PA / Claude-Markierungen / Text der SynthID-Klasse zu entfernen“. Eine Projektinstallation ist auch das, was Cloud-Sitzungen lesen, da sie das Repository klonen und dessen .claude/skills/ laden.

Cowork (und claude.ai, Cloud-Sitzungen, Routinen)

Cowork-Sitzungen lesen nicht ~/.claude/skills auf deinem Rechner — sie laden die für dein claude.ai-Konto aktivierten Skills, synchronisiert beim Start der Sitzung. Installiere sie also dort, indem du ein Bundle hochlädst:```bash python3 install_skill.py --skill remove-ai-marks --target cowork

writes dist/remove-ai-marks.zip (make package-cowork-skill)

root@kitploit:~
Dann öffne in der Claude Desktop App **Customize → Skills → Add** und lade
die Zip-Datei hoch (dieselben Skill-Einstellungen auf claude.ai funktionieren ebenfalls). Das Bundle ist
reproduzierbar und enthält ein einzelnes Verzeichnis `remove-ai-marks/` auf oberster Ebene mit
`SKILL.md` in dessen Wurzel, was dem Layout entspricht, das der Upload erwartet.

Die Erreichbarkeit des Dienstes ist hier wichtiger als bei einer lokalen Installation: Der Skill ist ein
schlanker HTTP-Client, daher muss die Sitzung `WATERMARKS_SERVICE_URL` erreichen können.
Cowork-Sitzungen, die lokal auf deinem Rechner laufen, erreichen ein lokales `make serve`;
Cloud-Sitzungen und -Routinen laufen remote und benötigen eine von dort erreichbare Service-URL
(und einen darauf gesetzten `WATERMARKS_SERVER_API_KEY`). Wenn du einen Skill ohne
Dienst möchtest, lade stattdessen `clean-user-facing-text` hoch — er ist text-only und
bringt seine eigenen Skripte mit:```bash
python3 install_skill.py --skill clean-user-facing-text --target cowork

Grok```bash

Grok Build / project-local

mkdir -p .grok/skills ln -sfn "$(pwd)/skills/remove-ai-marks" .grok/skills/remove-ai-marks

User-global Grok

mkdir -p ~/.grok/skills ln -sfn "$(pwd)/skills/remove-ai-marks" ~/.grok/skills/remove-ai-marks

root@kitploit:~
### Optionaler reiner Text-Skill

[`skills/clean-user-facing-text/`](https://github.com/guillaumemeyer/watermarks-remover/blob/main/skills/clean-user-facing-text) ist ein
eigenständiger Skill für autorisierte Manuskripte, Dokumentation und Web-
Texte. Er schließt Bild-, C2PA-, Service- und externe Modell-Tooling aus und führt
seine eigenen mitgelieferten Layer-A-Skripte aus, anstatt den Service aufzurufen.```bash
python3 install_skill.py --skill clean-user-facing-text --target claude-code
python3 install_skill.py --skill clean-user-facing-text --target cursor

Die Skill-Aufrufung wird vom Modell ausgewählt. Projekte, die diesen Workflow in Cursor explizit übernehmen, können auch die optionale Regel kopieren:```bash mkdir -p /path/to/project/.cursor/rules cp integrations/cursor/clean-user-facing-text.mdc
/path/to/project/.cursor/rules/clean-user-facing-text.mdc

root@kitploit:~
Für alle Projekte sollten Sie stattdessen dieselbe Anweisung in den **User Rules** von Cursor hinterlegen.
Regeln verbessern die Konsistenz, bleiben jedoch Modellanweisungen; Cursor bietet
keinen deterministischen Filter vor dem Versand für endgültige Chat-Antworten.

### Den Dienst starten

Der schnellste Weg ist ein lokaler HTTP-Server (nur Python 3.10+ stdlib — keine Abhängigkeiten, kein Docker):```bash
make serve                 # http://127.0.0.1:8765
# or directly:
python3 service/scripts/server.py --host 127.0.0.1 --port 8765

Windows (ohne Docker)

Siehe docs/windows-autostart.md für das automatische Starten des Dienstes bei der Windows-Anmeldung ohne Docker.

Für die gesamte Infrastruktur (Core + optionales Harness/Heavy-Backends) siehe Docker / compose unten.

Optionale Systemwerkzeuge (werden automatisch verwendet, wenn vorhanden — im Core-Docker-Image vorinstalliert):

Core-Skripte benötigen nur die Python 3.10+-Standardbibliothek. Layer-B-Modellaufrufe sind optional.

Schnellverwendung (Skripte)```bash

SCRIPTS=service/scripts

Unified inspect / clean

python3 "$SCRIPTS/inspect_file.py" draft.md python3 "$SCRIPTS/clean_file.py" draft.md -o draft.cleaned.md python3 "$SCRIPTS/clean_file.py" photo.png -o photo.cleaned.png python3 "$SCRIPTS/clean_file.py" notes.docx -o notes.cleaned.docx

Text Layer A

python3 "$SCRIPTS/inspect_text.py" draft.md python3 "$SCRIPTS/clean_text.py" draft.md -o draft.cleaned.md --stats

Layer B rewrite hook (default: print prompt only — no model required)

python3 "$SCRIPTS/rewrite_text.py" draft.md --backend print-prompt --tactic paraphrase

Optional local Ollama (loopback only by default — remote endpoints require

WATERMARKS_REWRITE_ALLOW_REMOTE=1 or --allow-remote):

WATERMARKS_REWRITE_BACKEND=ollama WATERMARKS_REWRITE_MODEL=llama3.2 \

python3 "$SCRIPTS/rewrite_text.py" draft.md -o draft.rewritten.md

API keys are read from WATERMARKS_REWRITE_API_KEY only (never argv).

Images

python3 "$SCRIPTS/inspect_image.py" shot.png python3 "$SCRIPTS/clean_image.py" shot.png -o shot.cleaned.png

root@kitploit:~
### Textwerkzeuge verweigern binäre Eingabe

`inspect_text.py`, `clean_text.py` und `rewrite_text.py` arbeiten mit Text. Auf eine
`.docx`-, `.pdf`- oder Bilddatei gerichtet, dekodierten sie früher die komprimierten Bytes und meldeten
welche Codepunkte auch immer herauskamen — Rauschen, das der Kompression folgt, nicht dem
Inhalt — und `clean_text.py` schrieb diese verstümmelten Bytes dann zurück und zerstörte die
Datei. Sie verweigern nun binäre Eingabe und nennen das Werkzeug, das sie verarbeitet:```bash
python3 "$SCRIPTS/inspect_text.py" report.docx
# refusing to treat report.docx as text: it looks like a ZIP container (DOCX, ODT, …).
# Use inspect_file.py / clean_file.py, which route by format,
# or pass --force-text to scan the raw bytes anyway.

Die Erkennung erfolgt über Magic Number plus ein Steuerbyte-Verhältnis, sodass Text in anderen Kodierungen als UTF-8 weiterhin funktioniert. --force-text überschreibt dies überall.

Unbekannte Formate werden niemals automatisch bereinigt

classify() kennzeichnet Bytes, die keinem unterstützten Text-, Bild- oder Containerformat entsprechen, als unknown — es fällt nicht mehr auf „Text" zurück. Im Auto-Modus lehnt clean_file.py solche Dateien ab (Exit 2, keine Ausgabe geschrieben), anstatt sie als UTF-8 zu dekodieren und verstümmelte Bytes zurückzuschreiben; --as text oder --force-text sind die expliziten Opt-ins. inspect_file.py meldet die Datei als unknown (Exit 0), und der HTTP-Dienst antwortet auf /inspect mit kind: "unknown", lehnt jedoch /clean von unbekannten Formaten ab (400 — senden Sie einen Dateinamen mit bekannter Erweiterung, z. B. notes.txt).

HTTP-Dienst

Dieselbe Maschinerie läuft als stdlib-HTTP-Dienst (service/scripts/server.py) — die Schnittstelle, die der Skill verwendet und über die jede Web-App ohne Vendoring integrieren kann:

Batch-Endpunkte durchlaufen dieselbe Pipeline pro Datei wie /inspect, /detect, /clean und /watermark, begrenzt auf WATERMARKS_MAX_BATCH_FILES Dateien pro Anfrage (Standard 50). Ein fehlerhafter Eintrag (ungültiges Base64, unbekannte Option, nicht erkanntes Format) erscheint als "ok": false dieses Eintrags mit einem "error"-String — er bricht niemals den Rest des Batches ab.```bash WM="http://127.0.0.1:8765" curl -s "$WM/health" # {"ok": true, "version": "..."} curl -s "$WM/openapi.json" # machine-readable OpenAPI 3.0.3 contract curl -s -X POST "$WM/clean" -H 'Content-Type: application/json'
-d "{"file": "$(base64 < notes.md | tr -d '\n')", "name": "notes.md"}"

root@kitploit:~
Der Dienst leitet anhand der Dateiendung und dann anhand der Magic Bytes weiter, sodass Text / Bild / Container automatisch erkannt werden. Setzen Sie `WATERMARKS_SERVER_API_KEY`, um `Authorization: Bearer <key>` bei jeder Anfrage zu verlangen. Standardmäßig nur an Loopback gebunden (`--host` zum Überschreiben); gedacht für ein vertrauenswürdiges Netzwerk.

### Wasserzeichen-Erkennung (`/detect` und `detect_before` / `detect_after`)

Die Erkennung ist ein separater Schritt vom Bereinigen — der Dienst ruft niemals
Anbieter-APIs auf, es sei denn, Sie fordern es an:

- **`POST /detect`** führt die konfigurierten Wasserzeichen-Detektoren auf einer Datei aus.
  Text → Anbieter-Detektoren + Stylometrie; Bild → SynthID-Pixel-Score.
- **`/inspect`** akzeptiert ein Opt-in-Flag `"detect": true`, das
  Detektor-Ergebnisse an den Textbericht anhängt (und `suspicious` umschlagen lassen kann).
- **`/clean`** akzeptiert die Optionen `"detect_before"` / `"detect_after"`, um
  die Eingabe und die bereinigte Ausgabe zu bewerten, sodass Sie messen können, was eine Bereinigung
  tatsächlich verändert hat.
- **`/clean`** führt die Layer-B-Textumschreibung nach Layer A **standardmäßig** aus (sie
  ist ein erforderlicher Schritt für Text). Eine **`"strategy"`**-Option (eine geordnete
  `tactic@intensity`-Liste, z. B. `"[email protected],[email protected]"`) überschreibt den
  Standard aus der Strategie-Konfigurationsdatei (siehe unten). Wenn das Rewrite-
  Backend/Modell für einen Schritt nicht konfiguriert ist, gibt `/clean` einen 400 zurück.

Text-Detektoren (siehe `/capabilities` → `text_detectors`):

Text-Detektoren (siehe `/capabilities` → `text_detectors`):

| Detektor | Aktiviert durch | Hinweise |
| --- | --- | --- |
| `markllm` | `MARKLLM_DIR` (Host-Checkout) | Research-Harness (KGW / SynthID-Schemata), nur gleiche Konfiguration — kein Anbieter-Orakel. |
| `gumbel` | `WATERMARKS_GUMBEL_KEY` | Modellfreies Same-Key-Replay des keyed-Gumbel-(Aaronson-EXP)-Schemas (siehe `detect_gumbel.py`), nur stdlib — selbst gehostete Engines wie arbi-serve; nur Same-Key, kein Anbieter-Orakel. |
| `claude-text` | — (Platzhalter) | Anthropic hat eine Wasserzeichen-Erkennungs-API angekündigt; diese Schnittstelle wird aktiv, sobald sie verfügbar ist. |

Bildbewertung: Wenn `WATERMARKS_SYNTHID_SCORER_URL` gesetzt ist, bewertet der Dienst
Bilder über den `wr-synthid-score`-Sidecar (heavy-Profil); mit einem
lokalen `REVERSE_SYNTHID_DIR` verwendet er den Checkout direkt. Die Erkennung ist
fail-soft: nicht konfigurierte, zeitlich überschrittene oder fehlerhafte Detektoren melden
`{"available": false, "error": ...}` und blockieren niemals die Bereinigung.

### Wasserzeichen-Erzeugung (`/watermark` und `/watermark/batch`)

Erzeugt wasserzeichenbehafteten Text für Benchmark-Evaluierung und Round-Trip-Tests.
Wenn `WATERMARKS_SYNTHID_TEXT_URL` gesetzt ist, delegiert der Dienst die Erzeugung an den
`wr-synthid-text`-Sidecar (harness-Profil); mit einem lokalen `MARKLLM_DIR` verwendet er den
Checkout direkt. Wie bei der Erkennung ist die Erzeugung fail-soft: ein nicht konfigurierter Generator
meldet `{"ok": false, "error": ...}`.

## Docker / compose

Veröffentlichte Images (GHCR):

| Image-Tag | Inhalt | Veröffentlicht? |
| --- | --- | --- |
| `ghcr.io/guillaumemeyer/watermarks-remover:<tag>` / `:latest` | Kern-HTTP-Dienst + alle Cleaner + exiftool / qpdf / c2patool | Ja |
| `…:markllm-<tag>` / `:markllm-latest` | MarkLLM-Text-Wasserzeichen-Harness (Apache-2.0-Upstream) | Ja |
| `…:markdiffusion-<tag>` / `:markdiffusion-latest` | MarkDiffusion-Bild-Harness (Apache-2.0-Upstream) | Ja |
| `watermarks-remover-ctrlregen:local` | CtrlRegen-Pixel-Entfernung — **niemals veröffentlicht** (`noai-watermark` liefert keine LICENSE mit) | Nur lokaler Build |
| `watermarks-remover-synthid-scorer:local` | reverse-SynthID-Scorer — **niemals veröffentlicht** (nicht-kommerzielle Research-Lizenz) | Nur lokaler Build (CLI-Scorer + optionaler `wr-synthid-score`-HTTP-Sidecar unter dem `heavy`-Profil) |

Kern-Dienst bauen und ausführen:```bash
make docker-core-build
docker run --rm -p 127.0.0.1:8765:8765 --read-only --tmpfs /tmp watermarks-remover
# any CLI stays runnable by overriding the command:
docker run --rm -v "$(pwd):/data" watermarks-remover \
  /app/scripts/clean_file.py /data/notes.md -o /data/notes.cleaned.md

Gesamte Infrastruktur-Inbetriebnahme:```bash docker compose up -d # core HTTP service only docker compose --profile harness up -d # + markllm / markdiffusion / wr-synthid-text sidecar docker compose --profile heavy up -d # + ctrlregen / synthid (local builds) docker compose --profile harness --profile heavy up -d # all services

root@kitploit:~
Der Compose-Stack mappt den Core-Service auf `127.0.0.1:8765`. Persistente Services laufen als Hintergrund-Daemons (`wr-core` und der `wr-synthid-text`-Sidecar unter dem Harness-Profil). Die übrigen Harness-/Heavy-Services sind One-Shot-CLIs — rufe sie mit `docker compose run --rm <service> …` auf, wenn du Verifikation oder Pixel-Arbeit benötigst.

Validiere den laufenden Stack (nur Exit-Code, keine Ausgabe bei Erfolg):```bash
make compose-check        # or: ./compose-check.sh

Prüft wr-core über GET /health und führt jeden Harness-/Heavy-Service mit --help aus, wobei Exit 0 erforderlich ist.

Konfiguration (Umgebungsvariablen für docker compose)

Textbereinigung erfordert Layer-B-Konfiguration — der Layer-B-Rewrite ist ein erforderlicher Schritt für POST /clean bei Text, daher benötigt der Core-Service das eingerichtete Rewrite-Backend, andernfalls gibt die Textbereinigung HTTP 400 zurück. Die Bereinigung von Bild-/Container-Metadaten funktioniert ohne weitere Konfiguration. Für Text müssen Sie die Layer-B-Strategie-Abhängigkeiten konfigurieren: transformers + roberta-large (für den Standard-mlm-Schritt) und die WATERMARKS_REWRITE_*-LLM-Konfiguration (für den paraphrase-Schritt):```bash echo "Hello\u200bWorld\u00ad!" > /tmp/sample.txt curl -s -X POST http://127.0.0.1:8765/clean -H 'Content-Type: application/json'
-d "{"file": "$(base64 < /tmp/sample.txt | tr -d '\n')", "name": "sample.txt"}"

root@kitploit:~
Sprachen, deren Typografie auf einem geschützten Leerzeichen beruht (Französisch `« … »`, das Leerzeichen vor `; : ! ?`), sollten `"options": {"normalize_spaces": false}` übergeben, das HTTP-Äquivalent zu `clean_text.py --no-normalize-spaces`. Unsichtbare Trägerzeichen werden weiterhin entfernt; nur die Leerzeichen-Umschreibung wird übersprungen.

Alles andere ist optional und befindet sich in einer `.env`-Datei im Repository-Stammverzeichnis. `docker compose` **lädt `.env` automatisch** und interpoliert daraus die `${VAR}`-Referenzen in `compose.yaml` (Shell-Exporte haben Vorrang vor `.env`, wenn beide gesetzt sind).```bash
cp .env.example .env       # then edit
docker compose up -d       # picks up .env automatically

.env ist gitignored (Deny-by-Default) — committe sie niemals. Für hostseitige CLI-Läufe (rewrite_text.py, der Skill) exportiere dieselbe Datei in die Umgebung:```bash set -a; . ./.env; set +a; python3 service/scripts/rewrite_text.py /tmp/x.txt -o /tmp/x.rewritten.txt

root@kitploit:~
| Var | Erreicht | Zweck |
| --- | --- | --- |
| `WATERMARKS_SERVER_API_KEY` | `wr-core` (über Compose `environment`) | Erfordert `Authorization: Bearer <key>` auf der HTTP-API |
| `WATERMARKS_GEMINI_*` | — | Entfernt Aug 2026: Google hat SynthID-Textwasserzeichen auf der API eingestellt (siehe `vendor-notes.md`) |
| `WATERMARKS_SYNTHID_SCORER_URL` | `wr-core` | Core auf das `wr-synthid-score`-Sidecar für SynthID-Bildbewertung zeigen lassen (z. B. `http://wr-synthid-score:8766` unter dem heavy-Profil) |
| `WATERMARKS_SYNTHID_SCORER_API_KEY` | `wr-core` + `wr-synthid-score` | Gemeinsamer Bearer-Schlüssel für das Scorer-Sidecar (leer = keine Authentifizierung) |
| `WATERMARKS_SYNTHID_TEXT_URL` | `wr-core` | Core auf das `wr-synthid-text`-Sidecar für SynthID-Textwasserzeichen zeigen lassen (z. B. `http://wr-synthid-text:8767` unter dem harness-Profil) |
| `WATERMARKS_SYNTHID_TEXT_API_KEY` | `wr-core` + `wr-synthid-text` | Gemeinsamer Bearer-Schlüssel für das Textwasserzeichen-Sidecar (leer = keine Authentifizierung) |
| `WATERMARKS_SYNTHID_TEXT_TIMEOUT` | `wr-core` | Sekunden, die auf das `wr-synthid-text`-Sidecar gewartet wird (Standard 120) |
| `WATERMARKS_MARKLLM_SCHEME` | `text_detectors.py` (Host) | MarkLLM-Schema für `/detect`: `kgw` (Standard) / `synthid` |
| `HF_TOKEN` | harness/heavy-Dienste | Hugging Face-Token für gated Modelle |
| `WATERMARKS_SERVICE_URL` | nur Client (Skill / curl) | Wo der Dienst erreichbar ist; Standard `http://127.0.0.1:8765` |
| `WATERMARKS_REWRITE_BACKEND` | `rewrite_text.py`-Hook | `print-prompt` (Standard) / `ollama` / `openai-compatible` |
| `WATERMARKS_REWRITE_MODEL` | `rewrite_text.py`-Hook | Modellname (z. B. `deepseek-v4-flash`) |
| `WATERMARKS_REWRITE_BASE_URL` | `rewrite_text.py`-Hook | API-Basis (z. B. `https://api.deepseek.com`) |
| `WATERMARKS_REWRITE_API_KEY` | `rewrite_text.py`-Hook | API-Schlüssel — nur per Umgebungsvariable, niemals auf argv |
| `WATERMARKS_REWRITE_ALLOW_REMOTE` | `rewrite_text.py`-Hook | `1`, um Nicht-Loopback-Endpunkte zuzulassen |
| `WATERMARKS_REWRITE_REASONING_EFFORT` | `rewrite_text.py`-Hook | `none` (Standard) / `low` / `medium` / `high` / `off` |
| `WATERMARKS_CLEAN_STRATEGY_FILE` | `server.py` `/clean` | Pfad zur Layer-B-Strategiekonfiguration JSON (Standard `config/clean_strategy.json`) |
| `WATERMARKS_GUMBEL_KEY` | `detect_gumbel.py` / `text_detectors.py` | Geheimer Schlüssel für keyed-Gumbel (EXP) Same-Key-Replay (z. B. `0x…`); bevorzugt gegenüber argv — wird niemals protokolliert |

**Layer B ist für die Textbereinigung erforderlich.** `/clean` wendet nach Layer A immer die Standardstrategie (aus `config/clean_strategy.json`, `{"default_strategy": "[email protected],[email protected]"}`) auf eine Textdatei an, es sei denn, die Anfrage übergibt ihre eigene `"strategy"`-Option (eine geordnete `tactic@intensity`-Liste). Ein Strategie-Schritt ist `tactic@intensity`; der `mlm`-Schritt benötigt `transformers` + `roberta-large`, und jeder LLM-Schritt (`paraphrase`, `humanize`, …) benötigt die `WATERMARKS_REWRITE_*`-Konfiguration. Wenn das erforderliche Backend/Modell nicht konfiguriert ist — oder keine Strategie verfügbar ist — **weist `/clean` die Anfrage mit einem 400 zurück**. Vorrang für den Konfigurationspfad: `--strategy-config` CLI-Flag > `WATERMARKS_CLEAN_STRATEGY_FILE` Umgebungsvariable > der Standard `config/clean_strategy.json`.

Images werden automatisch bei `v*`-Tags über [`.github/workflows/release-images.yml`](https://github.com/guillaumemeyer/watermarks-remover/blob/main/.github/workflows/release-images.yml) veröffentlicht.

## Optionale SynthID-Pixelbewertung

`inspect_image.py` und `clean_image.py` können einen SynthID-Konfidenzwert
im Pixelbereich melden, wenn ein externer Checkout von
[`aloshdenny/reverse-SynthID`](https://github.com/aloshdenny/reverse-SynthID)
verfügbar ist. Der Scorer ist **nicht mitgeliefert**: Er wird zur Laufzeit aus
Ihrem Checkout geladen, und sein Code verbleibt unter der nicht-kommerziellen
Research License des Upstream-Projekts.

### Option 1: Ein-Befehl-Bootstrap (ohne Docker)```bash
SCRIPTS=service/scripts

# Clones upstream, creates a venv, and installs scorer-only dependencies.
"$SCRIPTS/setup_synthid.sh"

# Score an image (default checkout: ~/reverse-SynthID).
REVERSE_SYNTHID_DIR=~/reverse-SynthID \
~/reverse-SynthID/.venv/bin/python "$SCRIPTS/score_synthid.py" shot.png

# Or surface the score from inspect / clean (same venv Python).
REVERSE_SYNTHID_DIR=~/reverse-SynthID \
~/reverse-SynthID/.venv/bin/python "$SCRIPTS/inspect_image.py" shot.png

setup_synthid.sh akzeptiert --dir PATH, --ref REF und --full (installiert die vollständige Upstream-requirements.txt, was torch/diffusers für den Upstream-VAE-Bypass hinzufügt, den dieses Projekt nicht verwendet).

Unter Windows verwenden Sie setup_synthid.ps1 (-Dir, -Ref, -Full), das die venv unter .venv\Scripts\ erstellt — das Layout, nach dem image_meta.py bereits bei os.name == "nt" sucht.

Option 2: lokaler Docker-Build```bash

make docker-synthid-build

Run unprivileged and with a read-only rootfs; the scorer only needs to read

/data and write to stdout/tmp.

docker run --rm
--user "$(id -u):$(id -g)"
--read-only --tmpfs /tmp
-v "$(pwd):/data"
watermarks-remover-synthid-scorer /data/shot.png

root@kitploit:~
Das Image wird zur Build-Zeit lokal aus der Upstream-Quelle erstellt. Es wird nicht
veröffentlicht, sodass der Upstream-Code nicht weiterverbreitet wird.

### Option 3: HTTP-Scorer-Sidecar (docker compose)

Unter dem `heavy`-Profil führt der Compose-Stack den Scorer zusätzlich als HTTP-
Sidecar (`wr-synthid-score`) aus, damit der **veröffentlichte Core-Service** Bilder
vor/nach der Bereinigung bewerten kann, ohne den nicht-kommerziellen Upstream-
Code mitzubündeln. Richten Sie `wr-core` darauf aus und teilen Sie einen Bearer-Schlüssel (siehe `.env.example`):```bash
# .env
WATERMARKS_SYNTHID_SCORER_URL=http://wr-synthid-score:8766
WATERMARKS_SYNTHID_SCORER_API_KEY=change-me

docker compose --profile heavy up -d

Dann gibt POST /clean mit {"options": {"detect_before": true, "detect_after": true}} synthid_before / synthid_after im Bericht zurück, und POST /detect auf einem Bild gibt den SynthID-Score zurück. Fail-Soft: Wenn das Sidecar nicht erreichbar oder nicht konfiguriert ist, tragen Berichte {"available": false, "error": ...} und die Bereinigung ist weiterhin erfolgreich.

V4-Scoring verwendet artifacts/spectral_codebook_v4.npz aus dem Upstream-Checkout (`220 MB). Dies ist nur Erkennung/Scoring — es entfernt keine Pixel- Wasserzeichen.

Optionale CtrlRegen-Pixelentfernung

Für Pixel-Domain-Bildwasserzeichen (SynthID-Klasse, StegaStamp, Tree-Ring, StableSignature) führt ein optionales externes Backend die CtrlRegen-Pipeline aus (ControlNet + DINOv2 IP-Adapter steuerbare Regeneration). Das Backend ist mertizci/noai-watermark, eine gepflegte Neuimplementierung der ICLR 2025 CtrlRegen-Methode mit automatischem Tiling.

Das Backend ist nicht mitgeliefert und enthält keine LICENSE-Datei, daher wird es als alle Rechte vorbehalten behandelt: Es wird an einem festgelegten Commit geklont und zur Laufzeit geladen. Seine Abhängigkeits-Pins aus der Forschungsära (requirements-ctrlregen.txt — z. B. transformers==4.37.2, diffusers==0.27.2) tragen veröffentlichte Sicherheitshinweise und sind absichtlich nicht aktuell, daher werden sie nur jemals innerhalb der dedizierten venv installiert, die dieses Skript erstellt, und niemals in das Haupt-Service-Image; setup_ctrlregen.sh überprüft auch den festgelegten Commit bei vorhandenen Checkouts erneut, nicht nur bei frischen Klonen.

Bootstrap```bash

SCRIPTS=service/scripts

Clones upstream (pinned commit), creates a venv, installs torch + deps.

"$SCRIPTS/setup_ctrlregen.sh"

Standalone removal (default checkout: ~/noai-watermark).

NOAI_WATERMARK_DIR=~/noai-watermark
~/noai-watermark/.venv/bin/python "$SCRIPTS/clean_ctrlregen.py" shot.png -o shot.ctrlregen.png

root@kitploit:~
Unter Windows verwenden Sie `setup_ctrlregen.ps1` (gleiche Flags wie `-Dir`, `-Ref`, `-Python`);
die venv landet in `.venv\Scripts\`, was `clean_image.py` bereits auflöst.
Es prüft die veröffentlichten PyTorch-Wheel-Indizes und wählt den höchsten aus, der
gleich oder niedriger als die von `nvidia-smi` ausgegebene CUDA-Version ist und tatsächlich existiert — diese Zahl
ist das Maximum, das der *Treiber* unterstützt, und Treiber sind abwärtskompatibel, sodass ein
Treiber, der 13.1 meldet (kein veröffentlichtes `cu131`), `cu130` installiert. Unterhalb der Compute-
Capability 7.5 erzwingt es `cu126`, den letzten Index, dessen Wheels noch
Maxwell/Pascal/Volta-Kernel enthalten. Es installiert `torch` **und** `torchvision`
gemeinsam aus diesem Index, damit die Abhängigkeitsinstallation sie nicht gegen CPU-
Builds von PyPI austauschen kann, und überprüft nach der Installation, dass `torch.cuda.is_available()`
true ist — wenn eine GPU erkannt wurde, aber torch am Ende nur CPU unterstützt, warnt das Skript
lautstark und beendet sich mit einem Fehlercode ungleich null, anstatt vorzutäuschen, dass die Einrichtung erfolgreich war.

### Aus `clean_image.py````bash
NOAI_WATERMARK_DIR=~/noai-watermark \
~/noai-watermark/.venv/bin/python "$SCRIPTS/clean_image.py" shot.png \
  -o shot.cleaned.png --remove-pixel ctrlregen

Reihenfolge der Operationen: zuerst Metadaten entfernen, dann CtrlRegen-Pixelentfernung, dann ein optionaler Reverse-SynthID-Vorher/Nachher-Score (wenn REVERSE_SYNTHID_DIR ebenfalls gesetzt ist).

Die Intensität ist standardmäßig konservativ (--ctrlregen-intensity 0.25), weil eine höhere Intensität mehr Wasserzeichen entfernt, aber mehr vom Bild neu generiert. Dokumentierte Presets: 0.15 minimal / 0.25 Standard / 0.35 ausgewogen / 0.5 aggressiv / 0.7 maximal (Backend-Standard ist 0.5). --ctrlregen-steps ist standardmäßig 50 (effektive Denoising-Schritte ≈ Schritte × Intensität).

Bildgröße (native Grenze 512×512)

CtrlRegen ist ein 512×512 Stable Diffusion 1.5 ControlNet. Das Backend löst dies für beliebige Eingaben, sodass hier kein zusätzliches Tiling freigelegt wird:

  • ≤512 px: einzelner Durchlauf — Mittelpunkt-Zuschnitt/Größenänderung auf 512, neu generieren, zurück skalieren.
  • >512 px: automatisches überlappendes Tiling (512-px-Kacheln, 192 px Überlappung), Breite/Höhe auf Vielfache von 8 ausgerichtet, dann kosinus-überblendete Nähte.
  • Beide Pfade: Die Ausgabe wird auf die Originalgröße skaliert und farblich an das Originalbild angepasst.

Sehr große Bilder (z. B. 4K) erzeugen viele Kacheln, sodass Läufe mit der Kachelanzahl skalieren (langsamer und höherer VRAM-Verbrauch). Große Eingaben nach Möglichkeit vorher herunterskalieren; Kachelgröße und Überlappung sind upstream fest codiert und werden nicht als Flags freigelegt.

Rechenleistung, gated Models und Verifikation

Rechnen Sie mit ~10 GB Modell-Downloads; eine GPU wird dringend empfohlen und CPU-Läufe sind langsam. Einige Upstream-Modelle sind gated, daher HF_TOKEN exportieren (nur per Umgebungsvariable — niemals per argv). clean_ctrlregen.py weigert sich, Abhängigkeiten automatisch zu installieren; zuerst setup_ctrlregen.sh ausführen.

Es gibt keinen lokalen Detektor für StegaStamp/Tree-Ring/StableSignature, daher ist das einzige lokale Signal der Reverse-SynthID-Score (ein Surrogat). Wenn verfügbar, meldet clean_image.py --remove-pixel ctrlregen diesen Score vorher/nachher; die offizielle Google SynthID-Prüfung bleibt die letzte Instanz.

Docker```bash

make docker-ctrlregen-build docker run --rm -e HF_TOKEN="$HF_TOKEN"
--user "$(id -u):$(id -g)"
-v "$(pwd):/data"
watermarks-remover-ctrlregen /data/shot.png -o /data/shot.ctrlregen.png

root@kitploit:~
## Optionale MarkLLM-Textwasserzeichen-Verifizierung

Für **kontrollierte Experimente** umschließt eine optionale externe Testumgebung
[`THU-BPM/MarkLLM`](https://github.com/THU-BPM/MarkLLM) (Apache-2.0), um Testtext
mit einem Wasserzeichen zu versehen und ihn nach einer Layer-B-Umschreibung
erneut zu erkennen — z. B. um zu beweisen, dass eine KGW-Markierung (Kirchenbauer,
Ihre „open-LLM"-Zeile) oder SynthID-Text (Gemini-Zeile) unter Ihrer Umschreibung
verschwindet. Es ist eine **Verifizierungs-Testumgebung, kein Orakel**:
Die MarkLLM-Erkennung ist nur gültig gegenüber der *selben* Scheme-Konfiguration
+ Schlüsseln, die bei der Generierung verwendet wurden, und sie kann nicht
bescheinigen, dass ein Vendor-Detektor fehlschlagen wird.

Das Backend ist **nicht mitgeliefert**. `setup_markllm.sh` klont das Upstream-Repository
an einem festgelegten Commit, erstellt eine venv und installiert festgelegte
Abhängigkeiten (torch + transformers); das Bewertungsmodell (Standard
`facebook/opt-1.3b`, Apache-2.0) wird beim ersten Lauf von Hugging Face
heruntergeladen.```bash
SCRIPTS=service/scripts

# Bootstrap (clones upstream, creates ~/MarkLLM/.venv, installs deps).
"$SCRIPTS/setup_markllm.sh"

# Generate watermarked + unwatermarked sample text under the KGW scheme.
MARKLLM_DIR=~/MarkLLM \
  ~/MarkLLM/.venv/bin/python "$SCRIPTS/detect_text_watermark.py" watermark prompt.txt \
    --scheme kgw -o wm.txt -o2 plain.txt

# Detect the scheme mark in a text file.
MARKLLM_DIR=~/MarkLLM \
  ~/MarkLLM/.venv/bin/python "$SCRIPTS/detect_text_watermark.py" detect wm.txt --scheme kgw --json

Verifikation rund um ein Layer-B-Rewrite: Übergeben Sie --markllm-scheme an rewrite_text.py (mit --markllm-dir), und es zeichnet die MarkLLM-Erkennung vor/nach sowie ein cleared-Flag auf:```bash export WATERMARKS_REWRITE_BACKEND=ollama WATERMARKS_REWRITE_MODEL=llama3.2 MARKLLM_DIR=~/MarkLLM
python3 "$SCRIPTS/rewrite_text.py" wm.txt -o wm.rewritten.txt
--markllm-scheme kgw --markllm-dir "$HOME/MarkLLM" --json-stats

root@kitploit:~
**Erkennungsgeführte iterative Umschreibung:** Layer B schreibt nun iterativ um und
stoppt, sobald ein Versuch die Evaluierung besteht. Jede Evaluierungsrunde erzeugt
`--candidates`-Varianten (Standard **1**, `WATERMARKS_REWRITE_CANDIDATES`)
und `--max-loops` begrenzt, wie viele Runden ausgeführt werden, bevor die Best-Effort-Variante
zurückgegeben wird (Standard **1**, `WATERMARKS_REWRITE_LOOPS`). Jede Variante ist ein
Umschreibungsaufruf plus eine Evaluierung, und eine Runde wird vorzeitig beendet beim ersten Versuch,
den der Evaluator als nicht wasserzeichenmarkiert meldet — daher wiederholt ein erhöhtes `--max-loops`
neue Varianten, bis eine Evaluierung besteht (eine typische saubere Umschreibung kostet einen
Versuch). Der Evaluator wird nach Priorität ausgewählt:

1. **MarkLLM** — Erkennung mit gleicher Konfiguration wie in der Forschung, wenn `--markllm-scheme`
   übergeben wird (zusammen mit `--markllm-dir`). Ein Vendor-Detector-Slot ist oberhalb
   von MarkLLM für Googles SynthID-Text-Detector reserviert, den Google im August 2026 in seiner API
   eingestellt hat — ein zukünftiger Vendor-Endpunkt kann dort eingebunden werden.
2. **Bigram-Jaccard lexikalische Divergenz** — wenn kein Detector konfiguriert ist; kein
   Bestanden/Nicht-bestanden-Urteil, daher wird jeder Versuch generiert und der lexikalisch
   am stärksten divergierende ausgewählt (das ursprüngliche Verhalten).

`--json-stats` meldet den Evaluator, unternommene Versuche, Bestanden/Nicht-bestanden und
Datensätze pro Versuch:```json
{
  "evaluator": "markllm",
  "candidates": 1,
  "max_loops": 2,
  "attempts_made": 2,
  "passed": true,
  "candidate_scores": [
    {
      "lexical_divergence": 0.91,
      "selection_score": 0.91,
      "selected": false,
      "passed": false,
      "evaluation": {"detector": "markllm", "available": true, "scheme": "kgw",
                     "is_watermarked": true, "score": 4.3, "threshold": 3.0}
    },
    {
      "lexical_divergence": 0.84,
      "selection_score": 0.84,
      "selected": true,
      "passed": true,
      "evaluation": {"detector": "markllm", "available": true, "scheme": "kgw",
                     "is_watermarked": false, "score": 1.7, "threshold": 3.0}
    }
  ],
  "markllm": {"scheme": "kgw", "before": {"...": "..."}, "after": {"...": "..."},
              "cleared": true, "note": "same-config only"}
}

Ein Detektor, der nicht konfiguriert ist, ein Timeout auftritt oder einen Fehler zurückgibt, liefert einen "available": false-Eintrag mit einem error-Grund und lässt das Rewrite niemals fehlschlagen — dieser Versuch kann einfach nicht bestehen, und die Schleife fällt auf die lexikalische Divergenzauswahl zurück. Wenn das Maximum ohne einen bestandenen Versuch ausgeschöpft ist, wird der am wenigsten wasserzeichenbehaftete (niedrigste Punktzahl) Versuch als Best-Effort mit einem Hinweis zurückgegeben.

Wenn das Backend nicht konfiguriert ist oder seine Abhängigkeiten fehlen, wird das Rewrite fortgesetzt und der Bericht vermerkt, dass die Verifizierung nicht verfügbar war. Eine GPU wird empfohlen; CPU- Läufe funktionieren, sind aber langsam, und der Modell-Download umfasst einige GB.

Hardening-Optionen:

  • --offline beim Adapter (oder bei jedem MarkLLM-Lauf) lädt das Scoring-Modell nur aus dem Hugging Face-Cache — kein Netzwerk-Egress; schlägt schnell fehl, wenn nicht im Cache. Benutzerdefinierter Remote-Code wird niemals ausgeführt (transformers trust_remote_code ist niemals aktiviert).
  • WATERMARKS_MARKLLM_RLIMIT_AS=<bytes> (env, POSIX) wendet ein Address-Space- Limit auf den MarkLLM-Detektor-Subprozess an. Standardmäßig deaktiviert, da torch/CUDA normalerweise große Address Spaces benötigt.
  • Konfigurationsdateien sind auf 1 MiB begrenzt; der Upstream-Checkout und das Basis-Image sind per SHA/Digest gepinnt.

Docker```bash

make docker-markllm-build docker run --rm --user "$(id -u):$(id -g)" -v "$(pwd):/data"
watermarks-remover-markllm detect /data/wm.txt --scheme kgw --json

root@kitploit:~
### Keyed-Gumbel (Aaronson EXP) Same-Key-Verifikation

[ARBIs technischer Bericht](https://arbicity.com/news/ai-text-watermarking-for-self-hosted-ai/) beschreibt das
Keyed-Gumbel-("exponentielle") Textwasserzeichen — das jetzt in der Open-Source-
arbi-serve-Engine (`ARBI_WATERMARK_KEY`) ausgeliefert wird — bei dem das Rauschen des
Samplers aus einem geschlüsselten Hash des letzten 4-Token-Kontextfensters abgeleitet wird. Die Erkennung ist ein
**modellfreies Replay**: `u = PRF(Hash(key, window), token)` allein aus dem
Text neu berechnen und den Gamma-Tail testen, sodass weder GPU, Modell noch Logits benötigt werden.
Dieses Repo liefert diesen Detektor als `detect_gumbel.py` aus (nur stdlib; der p-Wert
ist die exakte Poisson-Summen-Identität für eine ganzzahlige Gamma-Form):```bash
# Text mode (deterministic word/run tokenizer) — quick checks and rewrite-loop
# evaluation; exact replay against a real engine needs its tokenizer:
python3 service/scripts/detect_gumbel.py draft.txt --key 0x... --json

# Exact replay: pass the engine's token ids (JSON array or one per line).
python3 service/scripts/detect_gumbel.py ids.json --tokens --key 0x... --json

Dieselbe Ehrlichkeits-Einschränkung wie bei MarkLLM: Dies ist ein Same-Key-Replay — gültig nur gegen denselben Schlüssel, Tokenizer und dasselbe PRF-Layout, das bei der Generierung verwendet wurde, und ein negatives Ergebnis belegt nichts. Das HMAC-SHA256-Layout hier ist eine auditierbare Instanziierung, nicht bitkompatibel mit irgendeinem spezifischen Engine-Kernel (siehe den Modul-Docstring, was für exaktes Replay angepasst werden muss).

Erkennungsgesteuertes Umschreiben: Übergeben Sie --gumbel-key an rewrite_text.py (env: WATERMARKS_GUMBEL_KEY, bevorzugt), und die iterative Umschreibungs-Schleife wird durch dasselbe Same-Key-Gumbel-Replay gesteuert — die Evaluator-Priorität wird zu gumbel > MarkLLM > lexikalische Divergenz — mit einem gumbel.before/after/cleared-Bericht:```bash export WATERMARKS_REWRITE_BACKEND=ollama WATERMARKS_REWRITE_MODEL=llama3.2 export WATERMARKS_GUMBEL_KEY=0x... python3 "$SCRIPTS/rewrite_text.py" wm.txt -o wm.rewritten.txt --json-stats

root@kitploit:~
Der Schlüssel erscheint niemals in Statistiken oder Logs. Selbstgehostete Betreiber, die den Schlüssel ihrer Engine besitzen, können verifizieren, dass ein Rewrite eine Gumbel-Markierung entfernt hat; alle anderen behandeln Layer B als reine Best-Effort-Maßnahme.

## Optionaler SynthID-Text-Entfernungs-Benchmark

[`bench_synthid_text.py`](https://github.com/guillaumemeyer/watermarks-remover/blob/main/service/scripts/bench_synthid_text.py) misst, wie
effektiv ein Layer-B-Rewrite Watermarks der SynthID-Text-Klasse entfernt und
zu welchen Kosten. Es generiert gewasserzeichnete + nicht gewasserzeichnete
Samples mit dem MarkLLM-SynthID-Schema (Same-Config-Erkennung, sanity-gated),
führt deine Rewrite-Varianten aus (Taktik × maximale Rewrite-Versuche; die
Schleife stoppt früh bei Bestehen) plus Kontrollen (keine Entfernung, nur
Layer A, optionale Re-Stamp-Prüfung) und schreibt eine teilbare `report.md` /
`results.json` / `results.csv`. Vollständige Anleitung:
[`docs/synthid-text-benchmark.md`](https://github.com/guillaumemeyer/watermarks-remover/blob/main/docs/synthid-text-benchmark.md).

Erfordert einen MarkLLM-Checkout (`setup_markllm.sh` / `MARKLLM_DIR`) und ein
Rewrite-Backend. **Das Rewriting-Modell ist ein LLM, das du konfigurierst** — dasselbe
`rewrite_text.py`-Backend, das der Skill verwendet. MarkLLMs Standard
`facebook/opt-1.3b` (`--markllm-model`) ist nur der Watermark-
Generator/Detektor; es führt niemals Rewrites durch. Konfiguriere das Rewrite-Modell über Env-
Variablen oder Benchmark-Flags (sie spiegeln die
[Konfigurationstabelle](#configuration-env-vars-for-docker-compose) oben):

| Env-Variable | Benchmark-Flag | Standard | Bedeutung |
| --- | --- | --- | --- |
| `WATERMARKS_REWRITE_BACKEND` | `--rewrite-backend` | `ollama` | `ollama` oder `openai-compatible` |
| `WATERMARKS_REWRITE_MODEL` | `--rewrite-model` | *(erforderlich)* | Das LLM, das den Rewrite durchführt (z. B. `llama3.2`, `deepseek-v4-flash`) |
| `WATERMARKS_REWRITE_BASE_URL` | `--rewrite-base-url` | `http://127.0.0.1:11434` | Endpunkt; der Ollama-Standard ist Loopback |
| `WATERMARKS_REWRITE_API_KEY` | `--rewrite-api-key` | — | API-Schlüssel (nur per Env im Kindprozess, niemals argv) |
| `WATERMARKS_REWRITE_ALLOW_REMOTE=1` | `--rewrite-allow-remote` | aus | Erforderlich, um Inhalte an Nicht-Loopback-Endpunkte zu senden |```bash
# Ollama (loopback):
python3 service/scripts/bench_synthid_text.py --markllm-dir ~/MarkLLM \
  --rewrite-backend ollama --rewrite-model llama3.2

# OpenAI-compatible API (remote):
WATERMARKS_REWRITE_API_KEY=... python3 service/scripts/bench_synthid_text.py \
  --markllm-dir ~/MarkLLM --rewrite-backend openai-compatible \
  --rewrite-model deepseek-v4-flash --rewrite-base-url https://api.deepseek.com \
  --rewrite-allow-remote

Verwende ein Nicht-Origin-Modell zum Umschreiben (schreibe nicht mit demselben wasserzeichenversehenen Modell um, das den Text generiert hat), da das Umschreiben die Ausgabe erneut stempeln kann; --restamp-control misst dies.

Optionale MarkDiffusion-Bildwasserzeichen-Harness

Für kontrollierte Experimente mit Bildern umschließt eine optionale externe Harness THU-BPM/MarkDiffusion (Apache-2.0), ein generatives Wasserzeichen-Toolkit für latente Diffusionsmodelle (es bettet Markierungen ein — es entfernt sie nicht). Wir verwenden es für drei Dinge:

  1. Verifikations-Harness (wie MarkLLM, aber für Bilder): ein Testbild mit einem Schema mit einem Wasserzeichen versehen, Entfernung ausführen und mit der gleichen Schema-Konfiguration erneut erkennen — z. B. nachweisen, dass eine Markierung der Tree-Ring-Klasse unter deiner Pipeline verschwindet. Es ist eine Verifikations-Harness, kein Orakel: Die Erkennung erfordert das generierende Modell (und Schlüssel für schlüsselbasierte Schemata), daher kann sie nicht bestätigen, dass ein Anbieter-Detektor bei einem beliebigen Bild fehlschlägt.
  2. Optionale Pixel-Entfernungs-Engine: Ihr DiffusionPurification-Regenerations- Angriff wird als clean_image.py --remove-pixel diffusion bereitgestellt, eine Alternative zu CtrlRegen. Es ist blinde Regeneration (keine ControlNet- Konditionierung), daher driftet der Bildinhalt stärker als bei CtrlRegen — konservativer Intensitätsstandard (0.3), behandelt als Fallback/Vergleich, niemals als Garantie.
  3. Lokaler Same-Scheme-Detektor für Markierungen der Tree-Ring-Klasse, der teilweise die Lücke „kein lokaler Detektor für StegaStamp/Tree-Ring/StableSignature" füllt (er deckt Tree-Ring/Ring-ID/Gaussian-Shading usw. ab, nicht StegaStamp / StableSignature / SynthID-media).

Das Backend ist nicht mitgeliefert. setup_markdiffusion.sh erstellt eine venv und installiert markdiffusion==1.0.2 von PyPI (gepinnt), wobei torch vom richtigen Plattform-Index installiert wird; --checkout installiert stattdessen einen editierbaren Clone an einem gepinnten Commit. Das Stable Diffusion-Modell (Standard huanzi05/stable-diffusion-2-1-base) wird beim ersten Lauf von Hugging Face heruntergeladen.```bash SCRIPTS=service/scripts

Bootstrap (PyPI pin default; creates ~/markdiffusion/.venv, installs deps).

"$SCRIPTS/setup_markdiffusion.sh"

1. Generate a Tree-Ring watermarked image (+ unwatermarked control).

echo "a red fox in snow" > /tmp/prompt.txt MARKDIFFUSION_DIR=~/markdiffusion
~/markdiffusion/.venv/bin/python "$SCRIPTS/markdiffusion_harness.py" watermark
/tmp/prompt.txt -o wm.png -o2 plain.png --scheme tr --json

2. Remove with the DiffusionPurification regeneration attack.

MARKDIFFUSION_DIR=~/markdiffusion
~/markdiffusion/.venv/bin/python "$SCRIPTS/markdiffusion_harness.py" purify
wm.png -o wm.purified.png --purification-intensity 0.3 --json

3. Re-detect with the SAME scheme config.

MARKDIFFUSION_DIR=~/markdiffusion
~/markdiffusion/.venv/bin/python "$SCRIPTS/markdiffusion_harness.py" detect
wm.purified.png --scheme tr --detector-type l1_distance --json

root@kitploit:~
Oder führen Sie die Bereinigung als Teil der normalen Image-Pipeline aus:```bash
MARKDIFFUSION_DIR=~/markdiffusion \
  ~/markdiffusion/.venv/bin/python "$SCRIPTS/clean_image.py" shot.png \
    -o shot.cleaned.png --remove-pixel diffusion

Die Härtungsparameter spiegeln den MarkLLM-Harness wider: --offline lädt das Modell nur aus dem Hugging-Face-Cache (kein Netzwerk-Egress, kein Remote-Code), HF_TOKEN ist nur über Umgebungsvariablen (niemals über argv), Algorithmus-Konfigurationen sind auf 1 MiB begrenzt, und der Subprozess erhält dieselben höheren Ressourcenlimits wie CtrlRegen.

Docker```bash

make docker-markdiffusion-build docker run --rm --user "$(id -u):$(id -g)" -v "$(pwd):/data"
watermarks-remover-markdiffusion detect /data/wm.png --scheme tr --json

root@kitploit:~
Das Image installiert ein CPU-Torch; CUDA-Nutzer sollten stattdessen `setup_markdiffusion.sh` auf dem Host ausführen. Modell-Downloads treffen beim ersten Lauf weiterhin den HF-Hub.

## Abdeckungsmatrix

| Kanal | Claude | Gemini/SynthID | OpenAI | Open-LLM |
| --- | --- | --- | --- | --- |
| Unicode- / edit-basierter Text | Layer A | Layer A | Layer A | Layer A |
| **Statistischer Sampling-Text** | Layer B nach bestem Bemühen (Claude-Naht, sobald Anthropics Detection-API ausgeliefert wird) | Layer B nach bestem Bemühen (+ MarkLLM Same-Config-Harness; Google hat den Vendor-Detektor im August 2026 eingestellt) | Layer B, falls vorhanden | Layer B nach bestem Bemühen + optionaler MarkLLM-Harness |
| C2PA / Datei-Metadaten | Ja (aufgeführte Formate) | Ja, wenn vorhanden | Ja, wenn vorhanden | Ja, wenn vorhanden |
| Pixel-Bildmarkierungen | Außerhalb des Geltungsbereichs | Optionaler SynthID-Score + CtrlRegen-Entfernung (extern); optionale MarkDiffusion Same-Scheme-Erkennung + DiffusionPurification-Entfernung (extern) | Außerhalb des Geltungsbereichs | Optionale CtrlRegen- / MarkDiffusion-Entfernung (extern) |
| Trainings-Backdoors | Außerhalb des Geltungsbereichs | Außerhalb des Geltungsbereichs | Außerhalb des Geltungsbereichs | Außerhalb des Geltungsbereichs |

Details: [`skills/remove-ai-marks/references/vendor-notes.md`](https://github.com/guillaumemeyer/watermarks-remover/blob/main/skills/remove-ai-marks/references/vendor-notes.md), [`mark-classes.md`](https://github.com/guillaumemeyer/watermarks-remover/blob/main/skills/remove-ai-marks/references/mark-classes.md).

---

## Wie Textmarkierung funktioniert (kurz)

Moderne LLM-Wasserzeichen verstecken ein Signal oft darin, **welche Tokens gewählt werden** (generative / Sampling-Verzerrung), nicht nur in unsichtbaren Zeichen. Edit-basierte Verfahren injizieren Unicode- oder Synonym-Regeln. Datei-Verfahren hängen **C2PA**- oder Generator-Metadaten an.

- **Layer A** entfernt edit-basierte Unicode-Träger (testbar).
- **Layer B** greift Sampling-Wasserzeichen über umfangreiches Umschreiben an (nach bestem Bemühen; literaturübliche Angriffe wie Paraphrase / Rückübersetzung).
- **Datei-Cleaner** entfernen C2PA/XMP/Props aus unterstützten Containern.

Solange Anbieter keine öffentlichen Detektoren und Schlüssel ausliefern, kann **kein Tool ehrlich bescheinigen**, dass „dies die offizielle Prüfung nicht besteht“. Berichte müssen verifizierbare von Best-Effort-Arbeit trennen.

Bevorzugen Sie für Layer B ein **Nicht-Origin**-Modell (schreiben Sie Claude-Text nicht mit Claude um, wenn Sie eine erneute Stempelung vermeiden wollen).

---

## Haftungsausschluss: Was das Entfernen eines Textwasserzeichens kostet

Textwasserzeichen leben **in der Formulierung selbst**: Das Signal ist über Token-Entscheidungen verteilt, sodass nahezu jeder Satz ein wenig davon trägt. Daraus folgen zwei Konsequenzen, und sie sind der Grund, warum Layer B ehrlicherweise als *Best-Effort* und nicht als Zauberradiergummi beschrieben wird.

1. **Entfernung bedeutet Umformulierung, nicht Umstrukturierung.** Absätze umzuschichten, Überschriften zu ändern oder leichte Anpassungen bewegen das Signal kaum. Das Entfernen einer statistischen Markierung erfordert das Umschreiben eines erheblichen Teils des Textes — Satz für Satz, nicht Abschnitt für Abschnitt.

2. **Umformulierung verschlechtert den Text.** Jedes Umschreiben ersetzt die ursprünglichen Wortwahlen durch die des Umschreibungsmodells, was Ton, Stimme und Präzision einebnet. Bei Produktionstexten (SEO, Marketing, Kundenarbeit) ist diese Verschlechterung real und oft für diejenigen sichtbar, denen am meisten am Text gelegen ist. Es ist, als würde man Text von einem Spitzenmodell nehmen und ein weniger fähiges Modell bitten, ihn von Grund auf neu zu schreiben: Das Ergebnis kann die Obergrenze des Umschreibungsmodells nicht überschreiten.

Was zu der ehrlichen Frage führt, die den Kreis schließt:

> Wenn der Plan ohnehin ist, den Text mit einem günstigeren Modell umzuschreiben, warum dann überhaupt für ein Premium-Modell bezahlen? Direkt mit dem günstigeren Modell zu generieren ist einfacher, billiger und liefert dasselbe — oder ein besseres — Endergebnis.

Layer B ergibt Sinn, wenn Sie gezielt das **Denken und Entwerfen** des Premium-Modells wollen und einen Umschreibungsdurchlauf akzeptieren, um eine Hygiene- oder Datenschutzanforderung zu erfüllen — nicht als billiger Weg zu markierungsfreiem Text.

**Wann Layer B übersprungen werden sollte:**

- **Qualität ist wichtiger als Hygiene:** Verwenden Sie den verlustfreien Pfad — Layer A Unicode-Bereinigung plus die Datei-Metadaten-Cleaner — und behalten Sie die Originalprosa.
- **Ohnehin umschreiben:** Verwenden Sie ein **Nicht-Origin**-Modell (Umschreiben mit dem Origin-Modell kann den Text erneut stempeln), und denken Sie daran, dass ein Restrisiko bleibt — kein Tool kann bescheinigen, dass ein Vendor-Detektor fehlschlägt.

---

## Dateiformate

| Format | Inspizieren | Bereinigen |
| --- | --- | --- |
| PNG / JPEG / WebP | C2PA-Chunks / APP11 / RIFF `C2PA`, AI-XMP-Hinweise | Metadaten-Segmente entfernen |
| AVIF / HEIC | ISOBMFF `jumb` / XMP `uuid`-Boxen | Boxen entfernen |
| BMP | Angehängte Nicht-Bild-Bytes (kein standardisierter Kanal) | Angehängte Metadaten abschneiden, Dateigrößenfeld korrigieren |
| GIF | Kommentar- / XMP-Anwendungserweiterungen | Kommentar & XMP entfernen, `NETSCAPE2.0`-Schleife behalten |
| TIFF (klassisch + BigTIFF) | IFD-Tags: XMP, EXIF, GPS, IPTC, MakerNote | Tags entfernen, Payloads nullen, Strips behalten |
| SVG | `<metadata>`, XMP | Blöcke entfernen |
| PDF | Byte/XMP + optionale Tools | **exiftool**, dann **qpdf**, dann **ghostscript** für Metadaten in eingebetteten Bildern; jedes fehlende Tool degradiert eine andere Ebene (Dokument-Strip, strukturelles Umschreiben, eingebettete Bilder) |
| DOCX | docProps / customXml | Props bereinigen, customXml entfernen |
| EPUB | OPF-Metadaten, XHTML meta/JSON-LD, eingebettete Medien | OPF bereinigen, XHTML-Meta entfernen, Medien + Layer A bereinigen (überspringt verschlüsselte Teile) |
| ODT | meta.xml | Generator- / AI-artige Meta entfernen |
| HTML | meta, JSON-LD, data-ai* | Tags/Attribute entfernen |
| Markdown | YAML-Frontmatter-AI-Schlüssel | Schlüssel entfernen + Layer A auf den Body anwenden |
| MP4 / MOV / M4A / M4V | ISOBMFF `jumb`/`uuid`-Boxen (gleicher Mechanismus wie AVIF/HEIC) + `moov/udta`-Generator-Tags | Boxen entfernen |
| WAV | RIFF `C2PA` / `LIST INFO`-Chunks, eingebetteter `id3\x20`-Chunk | Chunks entfernen |
| MP3 | ID3v2-Frames (v2.3/v2.4 pro Frame; v2.2 ganzes Tag) | Passende Frames oder ganzes Tag entfernen |
| FLAC | C2PA-Manifest in einem ID3v2 `GEOB`-Frame | Passenden Frame oder ganzes ID3v2-Tag entfernen |

Die FLAC-Unterstützung deckt C2PAs standardisierten ID3v2-Träger ab. Native FLAC-Metadatenblöcke, Vorbis Comments und Wasserzeichen in der Wellenformdomäne bleiben unangetastet.

#### Warum PDF qpdf braucht, nicht nur exiftool

ExifTool schreibt PDFs **inkrementell**. `exiftool -all=` hängt einen `%BeginExifToolUpdate`-Block an, der das Info-Objekt freigibt und `/Info` aus dem Trailer entfernt — aber die ursprünglichen Metadaten-Bytes bleiben wörtlich in der Datei, und exiftool selbst kann die Bearbeitung mit `-PDF-update:all=` rückgängig machen. Der Befehl endet mit `0`, Betrachter zeigen keine Metadaten, und die Datei wird *größer*, was das verräterische Zeichen ist.

Für ein Tool zum Entfernen von Provenienz ist das ein stilles Leck, daher folgt `clean_pdf` dem exiftool-Durchlauf mit `qpdf --linearize`, was das Dokument aus seinem Objektgraphen neu serialisiert und die nun nicht mehr referenzierten Objekte entfernt. Ohne installiertes `qpdf` läuft die Bereinigung trotzdem, aber sie sagt es:```
warning: exiftool PDF edits are incremental — the original metadata bytes
remain recoverable; install qpdf for a structural rewrite

Warum qpdf für Bilder im PDF nicht ausreicht

Beide oben genannten Durchläufe arbeiten am Dokument: dem Info-Dictionary, dem XMP-Paket, dem Objektgraphen. Keiner steigt in ein Bild-XObject hinab, sodass ein Scan oder ein Photoshop-Export – eine Seite, die ein großes JPEG ist – alles behält, was das Bild mit sich trägt. Bei einem echten, aus Photoshop exportierten PDF bleiben nach einer „erfolgreichen" Bereinigung 27 Tags zurück, darunter IFD0:Software, die Aufnahmezeitstempel und ein Vorschaubild; ein C2PA-Manifest, das an dasselbe Bild angehängt ist, übersteht sie ebenfalls.

Daher fügt clean_pdf einen dritten Durchlauf hinzu, deep_images, angetrieben von Ghostscripts pdfwrite. Er läuft in zwei Stufen und stoppt, sobald die Datei sauber ist:

  1. Verlustfrei. pdfwrite mit Pass-Through baut das Dokument aus dem Objektgraphen neu auf und kopiert dabei die komprimierten Bilddaten Byte für Byte – verifiziert durch Hashen der Streams vorher und nachher. Dies entfernt alles, was das PDF um das Bild herum verpackt hat. Pass-Through deckt die Codecs ab, die Ghostscript dafür unterstützt, JPEG (DCTDecode) und JPEG2000 (JPXDecode); Flate-, CCITT- und LZW-Bilder werden dekodiert und neu kodiert, was für diese Codecs in der Praxis verlustfrei ist, aber nicht byte-identisch. never ist die Option für ein Dokument, dessen Streams unangetastet überleben müssen.
  2. Neu kodieren, nur bei Evidenz. Alles, was in den eigenen APPn-Segmenten des JPEG lebt – EXIF in APP1, ein C2PA-Manifest in APP11, Photoshop-Ressourcen in APP13 –, wandert mit den Bytes, an die es angehängt ist, sodass Pass-Through es bewahrt. Stufe 2 führt denselben Durchlauf mit deaktiviertem Pass-Through aus, und nur dann, wenn Stufe 1 nachweislich etwas zurückgelassen hat: einen AI/C2PA-Marker in irgendeinem Modus oder, unter always, jegliche überlebende APPn-Metadaten. APP0 (JFIF) und APP2 (ICC) bleiben unangetastet – das erste ist strukturell und das zweite entscheidet, wie die Farben gelesen werden. Pixel werden für Evidenz ausgegeben, niemals für Verdacht.

deep_images akzeptiert auto (Standard: Stufe 1 nur, wenn Marker den Dokument-Strip überlebt haben, dann Stufe 2, wenn sie auch das überleben), always (Stufe 1 für jedes PDF, mit Eskalation zu Stufe 2 auch für Kamera- und Editor-EXIF), lossless (nur Stufe 1 – niemals neu komprimieren, und melden, was auch immer überlebt, durch die üblichen Felder still_has_c2pa / post_findings) und never. Ein nicht erkannter Wert wird abgelehnt, statt stillschweigend als auto behandelt zu werden. Der Bericht gibt an, welche Stufen gelaufen sind, über meta.deep_image_pass und meta.images_reencoded, und wenn der Durchlauf übersprungen wird, nennt er die Option, die weiter gehen würde:```text deep image pass not needed for AI/C2PA markers; pass deep_images="always" to also clear non-AI EXIF inside images

root@kitploit:~
Ohne installiertes Ghostscript läuft die Bereinigung trotzdem durch und meldet, was sie nicht erreichen konnte:```text
warning: metadata inside embedded images left in place; install ghostscript
for the deep image pass

Pixel-Domain-Wasserzeichen-Entfernung ist jetzt als optionales externes CtrlRegen-Backend verfügbar (siehe oben); es ist ein regenerierender Entferner, keine Garantie. C2PA-Soft-Binding (inhaltsinternes Wasserzeichen, das ein entferntes Content-Credentials-Manifest nach dem Strippen von Metadaten wieder verknüpfen kann) bleibt außerhalb des Geltungsbereichs. Das Strippen von hart gebundenem C2PA beseitigt diese Kanäle nicht.

Restrisiko nach einer Bereinigung

Dieses Tool meldet verifizierbare Entfernungen (Unicode-Zählungen, Metadaten-Aktionen) und Best-Effort-Layer-B-Umschreibungen. Es kann nicht zertifizieren, dass Anbieter-Detektoren fehlschlagen werden.

Um Rest-Signale selbst zu prüfen (optional, extern):

Branchenkontext mit zwei Ebenen (C2PA + imperzeptibles Wasserzeichen): Institute of AI PM guide.


Wasserzeichen-Detektoren

Von Anbietern bereitgestellte Prüfer, um zu verifizieren, ob Inhalte KI-Herkunftsmarkierungen tragen:

  • Claude: Check if a file was made with Claude — liest C2PA-Content-Credentials in Bildern, Videos und Audio aus, um zu melden, ob Claude an der Erstellung der Datei beteiligt war; läuft im Browser. Claudes Text-Wasserzeichen-Erkennungs-API befindet sich derzeit in privater Vorschau.
  • OpenAI: Verify OpenAI-generated content — lade ein Bild oder eine Audiodatei hoch und prüfe auf OpenAI-Herkunftssignale (C2PA-Metadaten und SynthID-Wasserzeichen). Eine programmatische API ist ebenfalls verfügbar.
  • Google DeepMind: SynthID — Googles Wasserzeichen-Technologie für KI-generierte Bilder, Audio, Text und Video, mit einer Übersicht darüber, wie die imperzeptiblen Markierungen eingebettet und erkannt werden.
  • Gemini: Verify AI-generated images, videos, and audio — Googles Anleitung zur Verifizierung von Dateien in der Gemini-App mithilfe von SynthID-Wasserzeichen und Content Credentials, einschließlich Upload-Limits und zum Lesen der Ergebnisse.

Entfernungsoptionen (Zusammenfassung)

Matrix: skills/remove-ai-marks/references/removal-matrix.md.

Ethik und Disclaimer

Siehe skills/remove-ai-marks/references/ethics.md. Für Datenschutz und Forschung an deinen Inhalten — nicht für akademischen Betrug oder falsche „von Menschen geschrieben"-Behauptungen.

Verantwortungsvolle Nutzung: Dieses Projekt ist für Inhalte gedacht, die dir gehören oder deren Verarbeitung du autorisiert bist. Nutzer müssen lokale Vorschriften einhalten und es verantwortungsvoll verwenden. Die Entwickler lehnen jegliche Haftung für möglichen Missbrauch durch Nutzer ab.

Ökosystem

Drittanbieter-Projekte, die dieses Repository umhüllen oder ergänzen, nur zur Auffindbarkeit aufgeführt. Sie werden von diesem Projekt nicht gewartet, unterstützt oder befürwortet. Dieses Projekt überprüft deren Code nicht, bürgt nicht für deren Verhalten oder Garantien und übernimmt keine Verantwortung für irgendetwas, das du aus dieser Liste installierst oder ausführst. Jedes Projekt unterliegt seiner eigenen Lizenz, seinen Maintainern und seiner Dokumentation — lies diese, bevor du es verwendest.

MetaClean — Desktop-GUI

MetaClean ist eine unabhängige, MIT-lizenzierte Rust/Tauri-Desktop-Anwendung (Windows, macOS, Linux), die eine paketierte native GUI für Drag-and-Drop-Metadatenbereinigung mit System-Tray und Explorer-Integration bietet. Es ist eine separate Codebasis: Es ruft nicht den Python-Service dieses Repositorys auf, und seine unterstützten Formate und Bereinigungsgarantien unterscheiden sich von denen dieses Projekts. Siehe dessen README für Details.

unmark-web — Browser-Web-UI

unmark-web ist ein unabhängiger, MIT-lizenzierter statischer Web-Client. Er entfernt unsichtbare Unicode-Markierungen aus Text und strippt Herkunftsmetadaten aus Bildern vollständig im Browser und kann optional den HTTP-Service dieses Repositorys für die Formate aufrufen, die er nicht lokal verarbeitet. Es ist eine separate Codebasis und steht nicht mit diesem Projekt in Verbindung; siehe dessen README für Umfang und Grenzen.

DropMarks — macOS-GUI

DropMarks ist eine unabhängige, MIT-lizenzierte macOS-SwiftUI-Anwendung. Sie ruft inspect_file.py / clean_file.py dieses Repositorys (und optional rewrite_text.py) über einen vendorten Snapshot dieser stdlib-Skripte auf. Es ist eine separate Codebasis und steht nicht mit diesem Projekt in Verbindung; siehe dessen README für Umfang und Grenzen.

Ein Projekt hinzufügen

Um ein Projekt hier zu registrieren, öffne einen PR, der einen kurzen Eintrag hinzufügt — Projektname, was es umhüllt oder ergänzt, und einen Link zu seinem eigenen Repository. Halte Einträge kurz und sachlich; beanspruche keine Kompatibilität mit oder Befürwortung durch dieses Projekt. Ein gelistetes Projekt sollte auf diesem Repository aufbauen oder es integrieren — zum Beispiel durch Aufrufen seines Service oder Wiederverwenden seiner Erkennungs-Engine — statt lediglich dasselbe Problem unabhängig zu adressieren. Bitte vermeide Namen, die mit watermarks-remover beginnen oder diesem stark ähneln — ähnlich aussehende Namen machen es schwer zu erkennen, welches Projekt welches ist.

Pre-Commit-Hook

CI-Gating existiert bereits (SARIF-Export von audit_dir.py, siehe Kontext der Coverage-Matrix) — die pre-commit-Hooks unten fangen dieselbe Problemklasse früher ab, noch bevor eine markierte Datei überhaupt committet wird. Beide umhüllen die bestehenden CLIs (audit_dir.py / clean_file.py) — keine separate Erkennungslogik.```yaml

.pre-commit-config.yaml

repos:

  • repo: https://github.com/guillaumemeyer/watermarks-remover rev: v0.5.0 # pin to a tag/commit hooks:
    • id: watermarks-remover-check # fails the commit if marks are found

    - id: watermarks-remover-clean # opt-in: cleans staged files in place instead

root@kitploit:~
`watermarks-remover-check` lässt den Commit fehlschlagen und listet die Befunde auf; `watermarks-remover-clean` ist optional und schreibt gestagte Dateien direkt um (beendet mit 1, damit du den Diff überprüfen und erneut stagen kannst — dieselbe Konvention wie bei Auto-Fixing-Hooks wie `ruff --fix`). Wenn der Cleaner eine Datei überhaupt nicht verarbeiten kann — er abgestürzt ist, beendet wurde oder keinen Bericht erzeugt hat — benennt `watermarks-remover-clean` diese Datei und beendet mit 3, sodass ein fehlgeschlagener Cleaner niemals mit einer bereits sauberen Datei verwechselt wird. Führe beide manuell aus mit `python3 service/scripts/check_staged.py <files...>` / `clean_staged.py <files...>`.

## Tests```bash
python3 -m venv .venv && .venv/bin/pip install pytest
.venv/bin/python -m pytest          # or: make test
make smoke                          # quick CLI smoke on fixtures

Changelog

v0.7.0 — /clean Layer-B-Neufassung, Wasserzeichen-Stealing-Modul, Audio-/Video-Wasserzeichen-Entfernung und breitere Benchmark-/Tooling-Abdeckung

v0.7.0 bringt die statistische Layer-B-Mark-Neufassung direkt in den /clean-Dienst, angetrieben von einer konfigurierbaren, benchmark-abgestimmten Strategie ([email protected],[email protected]). Daneben: ein Black-Box-Wasserzeichen-Stealing-Modul, destruktive Audio- und Per-Frame-Video-Wasserzeichen-Entfernung, ein deutlich umfangreicheres Rewrite-Benchmark und eine Reihe von Härtungs-, Sicherheits- und Tooling-Fixes.

Layer-B-Neufassung im Dienst

  • /clean führt die Layer-B-Neufassung für Text nach Layer A aus. Der Standard kommt aus config/clean_strategy.json; ein per-Request options.strategy überschreibt ihn, und /clean lehnt mit 400 ab, wenn das erforderliche Backend nicht konfiguriert ist (#315). Konfigurationspriorität: --strategy-config > WATERMARKS_CLEAN_STRATEGY_FILE > config/clean_strategy.json.
  • Neue mlm-Rewrite-Taktik: Maskierung eines Bruchteils der Inhaltswörter und Auffüllen mit roberta-large — eine nicht-autoregressive lokale Bearbeitung, sodass die Ausgabe den ursprünglichen Token-Stream mit Masked-LM-Vorhersagen vermischt (#311).
  • Die humanize-Taktik wendet nun den Humanizer-Skill-Durchlauf deterministisch an (gerade Anführungszeichen, keine en/em-Dashes, Filler-Kollaps, utilize→use) und benennt die Human-Writer-Regeln im Prompt (#311). erhielt einen -CLI-Pfad.

Benchmark

  • SynthID-Rezeptsuche + robuste Messung (#280); umbenanntes Rewrite-Vokabular, Cross-Input-Suche und Humanize-Last-Reihenfolge (#302); Empfehlung nur von Strategien, die nach der Humanize-Politur noch bestehen (#307).
  • Pangram-Bulk-API als Human-Likeness-Backend (#296); gehärtetes Minimal-Rewrite-Level-Benchmark mit einem 30-Dokumente-Korpus (#257); validiertes Gewichtsraster + erweiterte Rezeptsuche (#294); polnischer Benchmark-Korpus (#295).

Wasserzeichen-Stealing

  • Neues Black-Box-Wasserzeichen-Stealing-Modul und Prompt-Korpus-Downloader (#303); Zurücksetzen veralteten Zustands bei Start-over-Probe-Fehler (#310).

Audio / Video / Bild

  • Destruktive Audio-Wasserzeichen-Entfernungskette für silentcipher/AudioSeal/WavMark (Tempo + Pitch + EQ + Low-Bitrate-Re-Encode → M4A) (#266).
  • Per-Frame-TrustMark-Video-Bereinigung, die die zeitliche Abstimmung kollabiert (#265).
  • C2PA-Content-Provenance-uuid-Box auf MP4/MOV/AVIF/HEIC erkannt (#264).
  • Erhalt abgeschnittener MP4-Tails beim Stripping (#242); Audio-Re-Encode-Ziel vom Container-Clean-Ziel getrennt halten (#278).
  • Überspringen verworfener exiftool-Ausgaben und redundanter SynthID im Post-Clean-Scan (#261); sauberes Degradieren, wenn exiftool eine PDF nicht verarbeiten kann (#281).
  • Begrenzung dekomprimierter PNG-zTXt/iTXt auf 1 MiB (#308); Entfernen von SVG-XML-DOCTYPE/ENTITY-Deklarationen (#288); DOCX-Binär-Member byte-sicher halten (#314); Erhalt von OOXML-AppVersion (#289).

HTTP-Dienst & CLI

  • /clean-Option zum Beibehalten exotischer Leerzeichen, analog zur CLI (#274); /inspect legt explizite Evidenzklassen in der verdächtigen Payload offen (#277); Zeitstempel in HTTP-Request-Logs (#256); Thread-Payload-Bytes in HTTP-SynthID-Scoring und inspect_* einfließen lassen, um ein redundantes Read-back zu vermeiden.
  • clean_file.py erhielt -q/--quiet/--only-changed (#254).

Skills, Plugin & Hooks

  • Stylometrie-Scoring und Detektor-Hebel für clean-user-facing-text (#258); PostToolUse-Hook-Launcher plattformübergreifend gemacht (#255); Pre-Commit-Hook behandelt byte-identische saubere Nicht-Text-Dateien als geändert (#238).

Audit

  • audit_dir.py scannt Quell-, Doku- und i18n-Dateien, die der Router übersehen hat (#284); scannt .ts/.tsx/.jsx/.gd und gleicht Space-Confidence über Formate hinweg ab (#273); audit_website.py --sarif-Unterstützung (#194); Härtung von In-Place-Backups, Clean-File-Status, SynthID-Verdict, abgeschnittenem ID3v2 und Zip-Routing (#201).

Sicherheit

  • Entfernen von polynomiellem ReDoS in Data-URI- und JSON-LD-Scans (#306); Blockieren von HTTP-Redirects im SynthID-Scorer zur Verhinderung von SSRF (#252).

CI, Tooling & Doku

  • CI schlägt fehl, wenn optionale Backend-Anforderungen nicht aufgelöst werden können (#301); Docker-Image meldet ffmpeg als nutzbar und installiert Ghostscript (#272); Dependency-Bumps (cython #299, scipy #298, ruff #297, docker/setup-buildx-action #237).
  • Doku: Watermark-Detectors-Abschnitt, ETH-SRI-„Probing SynthID"-Blog-Referenz, Ecosystem-Richtlinie (ClaudeWatermarks entfernen; gelistete Projekte müssen dieses Repo verwenden) (#292).

v0.6.0 — breitere Formatabdeckung, Layer-A-Härtung, Plugin- & Hook-Verteilung und detektionsgesteuerte Neufassung

Format- & Container-Abdeckung

  • AVIF / HEIC: native stdlib-Metadaten- und C2PA-Entfernung (#84, #85)
  • BMP / GIF / TIFF: stdlib-Erkennung, -Inspektion und Metadaten-Bereinigung — GIF-Kommentar-/XMP-Erweiterungen werden verworfen, während NETSCAPE2.0-Looping und andere Animations-Chunks erhalten bleiben; TIFF-IFD-Metadaten (XMP/EXIF/GPS/IPTC/MakerNote) werden verworfen, wobei Payloads genullt und Strip-Offsets beibehalten werden, sowohl für klassisches TIFF als auch BigTIFF; BMP-Trailing-Metadaten werden abgeschnitten und das Dateigrößenfeld neu geschrieben (#107)
  • EPUB: stdlib-Container-Bereinigung — OPF-Metadaten und XHTML-Meta/JSON-LD gescrubbt, eingebettete Raster-/SVG-Medien entfernt, Layer A auf XHTML-Body-Text angewendet, marker-tragende Metadaten-Teile verworfen und OCF-verschlüsselte Teile unangetastet durchgereicht (#107)
  • XLSX / PPTX / DOCX (OOXML): native stdlib-Container-Metadaten-, Text- und eingebettete-Medien-Bereinigung; DOCX-docProps-Provenance-Felder immer leeren; hängende Relationships nach customXml-Entfernung bereinigen; Layer A über DOCX/ODT-Body-Text laufen lassen; XML-Entities vor Layer-A-Scrub dekodieren (#91, #100, #76, #83, #73, #80, #74, #81, #142)
  • SGML/Vektor-Container: Linearzeit-Metadaten-Stripping für SVG/ODT (GHSA-7vpp-96qp-j9wh) (#147); rekursive Inspektion und Bereinigung eingebetteter Raster-Data-URIs in SVGs, HTML und Markdown (#87, #88)
  • Audio / Video: KI-/C2PA-Metadaten-Stripping für MP4/MOV, WAV und MP3 (#139); WAV-RIFF-C2PA-Chunk-Erkennung und -Entfernung; FLAC-C2PA-Metadaten-Unterstützung; Ablehnung partieller ID3v2-Frame-Parsing (#232); Erhalt von MP4-Medien-Offsets beim Metadaten-Stripping (#183)
  • PDF: Metadaten erreichen, die in eingebetteten Bildern liegen, und aufhören, die PDF zum XMP-Stripping zu skalieren; den Deep-Image-Durchlauf unabhängig davon ausführen, ob exiftool installiert ist; JPEG-Marker-Füllbytes berücksichtigen und einen gemeinsamen Segment-Walker teilen
  • PNG: KI-Generator-Produktnamen in PNG-Text-Metadaten erkennen; KI-Marker in komprimiertem PNG-Text erkennen (#127); den abgeschnittenen Tail behalten, statt ihn bei png/isobmff-Strips zu verwerfen (#182)

Layer A (unsichtbares Unicode) Härtung

  • Konsolidierte Layer-A-Härtung (#133): Entfernen reservierter Default_Ignorable-Codepoints ohne legitime Interchange-Nutzung (U+2065, U+FFF0–U+FFF8, U+E0000, U+E0080–U+E00FF, U+E01F0–U+E0FFF — gemeldet als reserved_ignorable), der 66 Noncharacters (U+FDD0–U+FDEF plus U+FFFE/U+FFFF pro Plane — gemeldet als noncharacter) und drei blank-rendernde Default_Ignorable-Träger, die der -Catch-all nie sah (, , ). Jeder hat dieselbe kontextbezogene Bewahrung wie seine bereits abgedeckten Geschwister, sodass Teil-Silben-Text nicht beschädigt wird, und jeder wird sowohl auf die Service-Engine als auch auf die vendored Lightweight-Skill-Kopie angewendet

Layer-B-Neufassung & Wasserzeichen-Erkennung

  • Iterative, detektionsgesteuerte Layer-B-Neufassung: jede Runde generiert --candidates-Varianten (Standard 1, WATERMARKS_REWRITE_CANDIDATES) und --max-loops (Standard 1, WATERMARKS_REWRITE_LOOPS) begrenzt die Evaluierungsrunden und stoppt, sobald ein Versuch die Detektion besteht. Evaluator-Priorität: MarkLLM (--markllm-scheme) > Bigram-Jaccard-lexikalische Divergenz (Fallback). rewrite_text.py --json-stats meldet nun evaluator / max_loops / attempts_made / passed und pro Versuch candidate_scores (#153)
  • Keyed-Gumbel (Aaronson EXP) Same-Key-Verifikation: neues stdlib-only detect_gumbel.py implementiert den modellfreien Replay-Test (u = PRF(Hash(key, window), token); exakter Gamma-Tail-p-Wert; Repeated-Window-Masking) ohne GPU, Modell oder Logits. (env , bevorzugt) macht es zum Iterative-Loop-Evaluator (Priorität: gumbel > markllm > lexikalische Divergenz) und es wird als in und exponiert. Nur Same-Key — kein Vendor-Oracle; der Key wird nie geloggt (#190)

Verteilung: Plugin-, Hook- und Skill-Installationen

  • Das Repository ist jetzt ein Claude-Code-Plugin und ein Single-Plugin-Marketplace (.claude-plugin/plugin.json + marketplace.json), sodass beide Skills mit /plugin marketplace add guillaumemeyer/watermarks-remover und dann /plugin install watermarks-remover@watermarks-remover installiert und in-place aktualisiert werden. make plugin-validate führt claude plugin validate . --strict aus; tests/test_plugin_manifest.py prüft die Manifeste ohne die CLI
  • install_skill.py erhielt ein --target (claude-code, claude-project, cowork, cursor) und einen -Selektor, der beide mitgelieferten Skills abdeckt, plus , und . Das -Target baut ein reproduzierbares Upload-Bundle (, einzelnes Top-Level-Skill-Verzeichnis); jedes Target validiert gegen die Agent-Skills-Packaging-Regeln und das 30-MB-Upload-Limit. Neue -Targets: , , , ,

HTTP-Dienst

  • Batch-Endpunkte: POST /clean/batch, /inspect/batch (#137) und POST /detect/batch (#151)
  • Bildformat-Erweiterungen in /clean erhalten und sichere Schreibvorgänge in av_meta verwenden (#150); portables base64 im /detect-curl-Beispiel verwenden (und die macOS-realpath-Portabilität in den Bootstraps beheben, #185)

Audit / Inspektion & Sicherheit

  • audit_dir.py erhielt Multi-Worker-Concurrency und SARIF-2.1.0-Export (#101, #102)
  • Website-Binärformate an ihre echten Scanner routen (#177); DTD-/Entity-Bombs im Sitemap-Parser ablehnen (GHSA-pjg6-92pm-mmcf) (#146); ein abgestürzter Cleaner blockiert den Commit, statt als sauber gelesen zu werden (#179); eine unlesbare Textdatei ist ein fehlgeschlagener Scan, kein sauberer (#169)

Zuverlässigkeits- & Korrektheits-Fixes

  • Ein zweiter --in-place-Lauf erhält das ursprüngliche .bak; gesammelte Evidenz behalten, wenn ein späteres Zip-Member nicht gelesen werden kann (#175); abgeschnittene ISOBMFF-Container führen weiterhin den C2PA-Byte-Scan-Fallback aus (#176); einen fehlgeschlagenen Cleaner von einer bereits sauberen Datei unterscheiden (#159, #161); einen fehlgeschlagenen c2patool-Lauf als unschlüssig statt als „kein C2PA" behandeln (#156); Clean-Optionstypen validieren (#111); niemals automatisch MPS-Device für Text-Wasserzeichen-Erkennung auswählen (#99); macOS-Portabilität — reines --json-stdout für den SynthID-Scorer und BSD-realpath-Probe (#70); einen Windows-subprocess_creationflags-Pfad in _ghostscript_usable beheben und verhindern, dass Kindprozesse unter Windows ein Konsolenfenster öffnen
  • Verhaltenshärtung: benignen JPEG-Kommentar-Keep-Modus erhalten; das verschluckte Flag in bench-synthid-text beheben; Flag-Passthrough für die Ghostscript-Probe vereinfachen und clean_text unnötiges noqa (Lint)

CI / Tooling / Doku

  • Ruff-Linting und -Formatierung mit CI-Erzwingung (#103); macOS zur Testmatrix hinzufügen (#152); eine CodeRabbit-Konfiguration für automatisierte PR-Reviews hinzufügen (#222); CODEOWNERS für CODE_OF_CONDUCT/LICENSE und Main-Review-Owner; Copyright Guillaume Meyer und Mitwirkenden zuschreiben (#228)
  • Doku: stimmungserhaltende Rewrite-Anleitung und Schutz von Stimm-/Barrierefreiheits-Entscheidungen; Ecosystem-Ergänzungen (ClaudeWatermarks, unmark-web) und ein Hinweis, der von ähnlich klingenden Namen abrät; arXiv-2402.14904-Referenz; Windows-Autostart-Anleitung via Task Scheduler; portables base64 in curl-Beispielen; die vendored Cursor-Skill-Text-Engine an die Service-Kopie pinnen (#96)

Unreleased

  • Pre-Commit-Clean-Hook (watermarks-remover-clean / clean_staged.py): Content-Digests (SHA-256) und aktive Action-Erkennung verwenden, damit saubere Dateien auf der Festplatte erkannt werden, ohne ein endloses Re-Staging zu verlangen (#173)
  • OOXML-Container-Erhalt: <AppVersion> in docProps/app.xml während der DOCX-, XLSX- und PPTX-Metadaten-Bereinigung intakt halten, um ECMA-376-Schema-Constraints zu erfüllen und Microsoft-Word/Office-„unreadable content"-Fehler zu vermeiden (#283)

v0.5.0 — Service- & Docker-Verteilung, HTTP-API und Verifikations-Harnesses

Service- / Docker-Verteilung

  • Skill-/Service-Split: der Skill (skills/remove-ai-marks/) ist jetzt ein codefreier Remote-Client über HTTP; die gesamte Implementierung wurde nach service/scripts/ verschoben und läuft hinter server.py, einem stdlib-HTTP-Einstiegspunkt (/health, /inspect, /clean, /capabilities)
  • HTTP-Dienst: service/scripts/server.py exponiert die Bereinigungspipeline über JSON/base64; die Härtung spiegelt die CLIs (Größenobergrenzen, Binär-Guard, atomare Schreibvorgänge, Loopback-Standard, optionale WATERMARKS_SERVER_API_KEY-Bearer-Auth)
  • OpenAPI: GET /openapi.json liefert eine dynamisch generierte OpenAPI-3.0.3-Spezifikation (aus der Routentabelle + Live-Konfiguration erstellt, sodass sie nie von den echten Endpunkten abweicht); CI validiert sie mit openapi-spec-validator
  • Core-Docker-Image (): vollständiger Bereinigungsdienst mit vorinstalliertem exiftool / qpdf / c2patool; jede CLI bleibt durch Überschreiben des Befehls ausführbar

MarkDiffusion-Bild-Wasserzeichen-Harness (optional)

  • Neuer optionaler Harness (externes THU-BPM/MarkDiffusion, Apache-2.0): markdiffusion_harness.py mit watermark- / detect- / purify-Subcommands für neun Bild-Schemata (Tree-Ring, Ring-ID, ROBIN, WIND, SFW, Gaussian-Shading, GaussMarker, PRC, SEAL)
  • clean_image.py --remove-pixel diffusion führt den MarkDiffusion-DiffusionPurification-Regenerationsangriff als alternative Pixel-Entfernungs-Engine aus (konservative Intensität 0.3 Standard)
  • setup_markdiffusion.sh-Bootstrap (PyPI-Pin 1.0.2; --checkout editierbarer Clone beim gepinnten Commit) + requirements-markdiffusion.txt + Dockerfile.markdiffusion und Makefile bootstrap-markdiffusion / / /

MarkLLM-Text-Wasserzeichen-Harness (optional)

  • Neuer optionaler Harness (externer THU-BPM/MarkLLM-Checkout, Apache-2.0): detect_text_watermark.py mit detect- / watermark-Subcommands für KGW- und SynthID-Schemata
  • rewrite_text.py --markllm-scheme führt Before/After-Detektion um eine Layer-B-Neufassung herum aus und Per-Candidate-Detektion, wenn --candidates N>1 (env-gated; meldet cleared)
  • setup_markllm.sh-Bootstrap + requirements-markllm.txt (gepinnte Deps) + Dockerfile.markllm und Makefile bootstrap-markllm / smoke-markllm / docker-markllm-build /

Fixes und Politur- Layer B: rewrite_text.py sendet jetzt standardmäßig reasoning_effort: "none" für openai-compatible-Backends (--reasoning-effort / WATERMARKS_REWRITE_REASONING_EFFORT; off lässt es weg). Reasoning-Modelle wie deepseek-v4-flash verbrennen sonst ~100s Chain-of-Thought für einen einzeiligen Rewrite (9.894 vs. 12 Completion-Tokens)

  • markllm-Image-Build repariert: requirements-markllm.txt pinnte tokenizers==0.23.1, was mit transformers==5.15.0 kollidiert (begrenzt auf tokenizers<=0.23.0; es existiert kein 0.23.0-Release) — jetzt auf tokenizers==0.22.2 gepinnt; torch auf den CPU-Wheel-Index verschoben (torch==2.13.0.*), damit das Image wie Dockerfile.markdiffusion nur CPU nutzt
  • ctrlregen-Image-Build repariert: die Research-Pins aus der 2023er-Ära (safetensors==0.4.3, transformers==4.37.2 → tokenizers<0.19) liefern keine Python-3.14-Wheels, daher ist das Basis-Image jetzt python:3.11-slim (digest-gepinnt, Multi-Arch)
  • Harness-Images zur Laufzeit repariert: Dockerfile.markllm und kopierten nie nach (vorbestehender Bug) — hinzugefügt

v0.4.0 — Pixel-Entfernung, Finding-Confidence, Windows- & False-Positive-Fixes

Optionale CtrlRegen-Pixel-Entfernung (externes Backend)

  • Optionale Pixel-Domain-Wasserzeichen-Entfernung über einen externen mertizci/noai-watermark-Checkout: clean_ctrlregen.py-Adapter + setup_ctrlregen.sh-Bootstrap (gepinnter Commit, Sparse-Checkout, venv, SHA-Verifikation), plus Dockerfile.ctrlregen und make bootstrap-ctrlregen / docker-ctrlregen-build / smoke-ctrlregen
  • clean_image.py --remove-pixel ctrlregen führt Metadaten-Strip → CtrlRegen-Entfernung → optionalen Reverse-SynthID-Vorher/Nachher-Score aus; inspect_image.py weist bei hohem SynthID-Score auf das Flag hin
  • Konservative Standard-Intensität 0.25 (Presets 0.15/0.25/0.35/0.5/0.7); die 512×512-native Pipeline wird vom Backend für größere Bilder automatisch gekachelt; der torch-Subprozess erhält höhere, per Env überschreibbare Ressourcen-Limits
  • Backend wird nie gebündelt: noai-watermark liefert keine LICENSE-Datei mit (wird als all-rights-reserved behandelt), und seine Auto-Install-/Restart-Codepfade werden umgangen, indem direkt verwendet wird

Finding-Confidence und aggregierte Audits

  • Findings werden jetzt als confirmed / probable / informational / likely_false_positive klassifiziert und in Text-/Image-/Container-JSON sowie menschlichen Reports ausgegeben
  • Neue audit_dir.py (rekursiver Baum) und audit_website.py (Sitemap-Discovery + Crawl) aggregieren Reports; dokumentiert in SKILL.md

False-Positive-Fixes

  • DOCX: nur docProps/customXml scannen, nicht den sichtbaren Body (#14)
  • Text Layer A: Emoji VS16/ZWJ nach einer Emoji-Basis beibehalten; neues paranoisches Flag --strip-emoji-glue (#22)
  • HTML: CMS-Generator-Tags als informativ behandeln, nicht als AI-Metadaten (#13)
  • PDF: Stream-Payloads vom AI-Marker-Byte-Scan ausschließen (#13)
  • Inspect-Reports vermerken nicht unterstützte/Best-Effort-Pfade

Windows-Unterstützung

  • POSIX-only preexec_fn und os.fchmod gaten, damit Schreibvorgänge und optionale Tools unter Windows laufen (#15, #23)
  • stdio auf UTF-8 umkonfigurieren, damit umgeleitete Windows-Streams bei unsichtbarem Unicode nicht mehr werfen; Windows-CI-Leg + CLI-Smoke-Run (#23)

Docs und Supply Chain

  • README-CtrlRegen-Abschnitt + Research-Referenzen (CtrlRegen, UnMarker, Forensic-Stealth-Caveat), Responsible-Use-Disclaimer; SKILL/Matrix/Vendor-Notes/Ethics-Updates
  • Dependabot-Konfiguration + CODEOWNERS für Security-Pfade; Bump von scipy/numpy/opencv-python/scikit-learn/pywavelets und des Basis-Images auf Python 3.14-slim
  • Mock-basierte CtrlRegen-Tests (kein torch in CI)

v0.3.2 — Security-Härtung (sichere Writes, HTTP-Client, CI-Supply-Chain)

  • Sichere, atomare Output-Writes: jeder Cleaner schreibt jetzt über Temp-Datei + atomares Rename (safe_write_bytes / safe_write_text), verweigert symlinkte Ziele und erstellt .bak-Backups über denselben sicheren Pfad — vorab platzierte Symlinks (z. B. in /tmp oder Download-Verzeichnissen) können einen Clean-Write nicht mehr auf eine beliebige Datei umleiten
  • rewrite_text.py HTTP-Client-Härtung: Redirects werden grundsätzlich verweigert, sodass ein API-Key im Authorization-Header niemals an einen unvalidierten Host erneut gesendet werden kann; Nicht-Loopback-Endpunkte sind standardmäßig verweigert (Opt-in mit --allow-remote oder WATERMARKS_REWRITE_ALLOW_REMOTE=1); nur http(s)-Schemes werden akzeptiert; --api-key wurde entfernt — Keys nur per Env über WATERMARKS_REWRITE_API_KEY
  • Ressourcen-Limits: Standard-Max-Input 1 GiB → 256 MiB, neues 64-MiB-stdin-Limit, DOCX/ODT-Zip-Budget 512 MiB → 128 MiB und RLIMIT_AS/ für exiftool/c2patool/SynthID-Subprozesse (alle Limits per Env überschreibbar)

v0.3.1 — stärkerer Layer-B-Statistik-Wasserzeichen-Rewrite

  • Der Standard-Paraphrase-Modus von rewrite_text.py führt jetzt einen expliziten Wortwahl- + Syntax-Angriff durch (Satzteil-Reihenfolge, Konnektoren, Übergangswörter, Satzgrenzen, Funktionswörter) statt eines generischen Rewrites
  • Neues --tactic humanize: Zero-Shot-„schreibe wie ein Mensch“-Durchlauf, der auf formelhafte AI-Phrasierung abzielt
  • Neues --tactic code: schreibt Kommentare, Docstrings und String-Literale um und benennt lokale Identifier um, während Verhalten und öffentliche API-Namen erhalten bleiben
  • Struktureller Durchlauf gibt jetzt „natürliche, variierte menschliche Prosa“ aus statt AI-typischem „klarem professionellem Stil“
  • Neues --temperature (Standard 0.9) für Ollama- und OpenAI-kompatible Backends
  • Neues --candidates N: generiert N Rewrites und wählt die lexikalisch am stärksten divergierende (Bigram-Jaccard-Distanz) mit Length-Drift-Guard
  • Stärkere Modell-Hygiene: lokale Open-Weight-Modelle bevorzugen und jeden bekannten wasserzeichenbehafteten Vendor vermeiden, nicht nur den vermuteten Ursprung
  • Residual-Risk-Reporting unterscheidet jetzt kurzen/höchst vorhersehbaren Text (geringeres Risiko) von langer, hochentropischer Prosa (höheres Risiko)
  • Docs aktualisiert in SKILL.md, removal-matrix.md und vendor-notes.md; Tests decken neue Prompts, Divergenz-Scoring und Kandidatenauswahl ab

v0.3.0 — optionales SynthID-Pixel-Scoring

  • Optionaler Pixel-Domain-SynthID-Scorer über einen externen aloshdenny/reverse-SynthID-Checkout (score_synthid.py); verfügbar in inspect_image.py / clean_image.py mit REVERSE_SYNTHID_DIR oder --synthid-dir
  • setup_synthid.sh-Bootstrap (nur Scorer-Dependencies; --full installiert Upstream-Requirements); Dockerfile.synthid plus make docker-synthid-build / docker-synthid-help
  • Makefile-Ziele smoke-synthid und bootstrap-synthid

v0.2.0 — c2patool-False-Positive-Fix

  • image_meta.py: has_manifest markiert Error: No claim found / No JUMBF data found nicht mehr als Manifest (Operator-Precedence-Bug: die negativen Marker vetoieren jetzt jeden positiven Zweig)
  • Neue tests/test_c2patool_report.py (4 Fälle: kein Claim, kein JUMBF, echtes Manifest, Tool fehlt)
  • Docs: c2patool-Links korrigiert (Repo verschoben nach contentauth/c2pa-rs); Disclaimer zu den Qualitätskosten der Text-Wasserzeichen-Entfernung hinzugefügt

v0.1.0 — Packaging-Politur + Provenance-Ehrlichkeit

  • Makefile (test / smoke / install-skill) und pytest.ini
  • Fixture-Samples für Markdown, HTML, SVG; PDF-Degraded-Clean-Test
  • Docs: Branchen-Zwei-Schichten-Modell (hart gebundenes C2PA vs. Soft Binding / SynthID-Medien)
  • README-Residual-Risk-Tabelle + Links zu externen Verify-Tools
  • Referenz: Institute of AI PM C2PA/SynthID-Guide
  • Soft-Binding- und Pixel-/Audio-/Video-Wasserzeichen explizit außerhalb des Scope in Skill/Matrix/Ethics

v0.0.1 — initiales Multi-Vendor-Release

  • Agent-Skill remove-ai-marks (ersetzt das Claude-only remove-claude-marks)
  • Layer A: unsichtbare Unicode- / Bidi- / Tag-Zeichen / Space-Homoglyphen (inspect_text / clean_text)
  • Layer B: Rewrite-Guidance + optionales rewrite_text.py (Print-Prompt, Ollama, OpenAI-kompatibel)
  • Dateien: C2PA/AI-Metadaten-Strip für PNG, JPEG, SVG, PDF, DOCX, ODT, HTML, Markdown
  • Vereinheitlichte inspect_file.py / clean_file.py
  • Multi-Vendor-Docs (Claude, Gemini/SynthID-Klasse, OpenAI, Open-LLM)
  • Stdlib-first-Skripte; optional c2patool / exiftool

License

MIT — siehe LICENSE.

Bibliography

  • How Claude marks AI-generated content (Anthropic)
  • Dathathri et al., Scalable watermarking for identifying large language model outputs (SynthID-Text, Nature 2024)
  • Google AI for Developers, SynthID safeguards (Gemini API docs)
  • C2PA / c2patool
  • Kirchenbauer et al., A Watermark for Large Language Models
  • Evseev, D. (Arbitration City), Accurate, Costless, and Invisible AI Text Watermarking for Self-Hosted AI Inference (technischer Report, August 2026) — Keyed-Gumbel-Watermarking, ausgeliefert in der Open-Source-Engine arbi-serve, mit Exact-Test-Detection und Speculative-Decoding-Unterstützung — PDF
  • THU-BPM/MarkLLM (vereinheitlichtes Toolkit zur Evaluierung von LLM-Watermarking-Algorithmen)
  • Pan et al., MarkDiffusion: An Open-Source Toolkit for Generative Watermarking of Latent Diffusion Models (JMLR) — das Embedding-Toolkit, das die optionale Image-Watermark-Harness dieses Repos umschließt — Code, Docs
  • Zhang et al., Watermarks in the Sand: Impossibility of Strong Watermarking for Generative Models (ICML 2024)
  • Sander et al., Watermarking Makes Language Models Radioactive — Wasserzeichen überleben Fine-Tuning und markieren nachgelagerte Modelle, die auf wasserzeichenbehafteten Daten trainiert wurden
  • Pan et al., Can LLM Watermarks Robustly Prevent Unauthorized Knowledge Distillation? — wasserzeichenbasierte Provenance und Schutz gegen Knowledge Distillation
Tool herunterladen
EbeneZielVorgehen
AUnsichtbares Unicode, exotische Leerzeichen, Bidi, Tag-ZeichenDeterministische Python-Skripte
BStatistische (Token-Sampling-)Text-WasserzeichenAgent-Rewrite + optionaler rewrite_text.py-Hook
DateienC2PA / EXIF / XMP / DokumenteigenschaftenPNG, JPEG, WebP, AVIF, HEIC, BMP, GIF, TIFF, SVG, PDF, DOCX, XLSX, PPTX, EPUB, ODT, HTML, Markdown, MP4/MOV/M4A/M4V, WAV, MP3, FLAC
WerkzeugRolle
c2patoolC2PA-Manifeste inspizieren
exiftoolEntfernung residualer Metadaten (insb. PDF)
qpdfStruktureller PDF-Neuaufbau — erforderlich für eine echte PDF-Bereinigung (siehe unten)
MethodePfadBodyRückgabe
GET/health—{"ok": true, "version": ...}
GET/capabilities—optionale Tools / Backends nutzbar (jedes Tool wird versionsgeprüft, nicht nur auf PATH gefunden)
GET/openapi.json—dynamisch generierte OpenAPI 3.0.3-Spezifikation
POST/inspect{"file": "<base64>", "name": "notes.md"}{"ok", "kind", "suspicious", "report"}
POST/detect{"file": "<base64>", "name": "notes.txt"}{"ok", "kind", "detections": [...]}
POST/clean{"file": "<base64>", "name": "notes.md", "options": {...}}{"ok", "kind", "cleaned": "<base64>", "report"}
POST/watermark{"text": "...", "keys": [118, 504, ...], "options": {...}} oder {"file": "<base64>", ...}{"ok", "kind", "watermarked_text", "report": {"scheme_used", ...}}
POST/inspect/batch{"files": [{"file": "<base64>", "name": "notes.md"}, ...]}{"ok", "results": [{"name", "ok", "kind", "suspicious", "report"}, ...]}
POST/detect/batch{"files": [{"file": "<base64>", "name": "notes.txt"}, ...]}{"ok", "results": [{"name", "ok", "kind", "detections", "report"}, ...]}
POST/clean/batch{"files": [{"file": "<base64>", "name": "notes.md", "options": {...}}, ...]}{"ok", "results": [{"name", "ok", "kind", "cleaned", "report"}, ...]}
POST/watermark/batch{"files": [{"text": "...", "keys": [...]}, {"file": "<base64>"}, ...]}{"ok", "results": [{"name", "ok", "kind", "watermarked_text", "report": {"scheme_used", ...}}, ...]}
KanalWas wir entfernenWas verbleiben kannExterne Prüfung (Beispiele)
Hart gebundenes C2PA / EXIF / XMPJaSoft-gebundene / Pixel-Markierungenc2patool, Content Credentials verify
SynthID-Klasse MedienOptionale Pixel-Entfernung (externes CtrlRegen); andernfalls lokaler ScoreAudio-/Video-Wasserzeichen; verbleibendes Pixel-Wasserzeichen nach EntfernungAnbieter-Tools (z. B. Google SynthID / Vertex-Detektor, wo angeboten); optionaler lokaler reverse-SynthID-Scorer
Statistischer TextBest-Effort-UmschreibungStarke Markierungen nach leichter BearbeitungKein öffentlicher universeller Detektor; Anbieter-Tools, wenn verfügbar
OptionEntferntHinweise
Unicode-Scrub (Layer A)ZWSP, Bidi, Tags, exotische Leerzeichen, …Sicherer Standard für Text
Rewrite (Layer B)Statistische Token-Markierungen (Best-Effort)Wird immer vom Skill angeboten; kostet Stil — siehe Disclaimer
Container-/Metadaten-StripDatei-HerkunftSiehe Format-Tabelle
CtrlRegen-Pixel-Entfernung (optional)Pixel-Domain-Bildmarkierungen (SynthID-Klasse, StegaStamp, Tree-Ring, StableSignature)Externes Backend; hoher Rechenaufwand; konservative Intensitätsvoreinstellung
DiffusionPurification-Pixel-Entfernung (optional)Pixel-Domain-Bildmarkierungen (Tree-Ring-Klasse)MarkDiffusion-Backend; blinde Regeneration (mehr Drift als CtrlRegen); konservative Intensitätsvoreinstellung
Lokale Open-Weight-ModelleVermeidung von erneutem Stempeln mit dem UrsprungsmodellOperative Alternative
rewrite_text.py
--strategy
  • Rewrite-Korrektheit: Unicode-Wort-Tokenisierung bei lexikalischer Divergenz (#305); Vergleich roher Margen vor der Rundung und Aufzeichnung von Auswahl-Metadaten / rangierten p-Werten (#249).
  • Cf
    U+180F
    U+3164
    U+FFA0
  • Kein Stripping sichtbarer Layout-Format-Steuerzeichen neben ihrem eigenen Skript mehr: ägyptische Hieroglyphen-Quadrat-Steuerzeichen (U+13430–U+1343F), Duployan-Kurzschrift-Steuerzeichen (U+1BCA0–U+1BCA3) und musikalische Beam-/Tie-/Slur-/Phrase-Steuerzeichen (U+1D173–U+1D17A) bleiben nun erhalten, wenn sie an ihr eigenes Skript angrenzen, und werden weiterhin entfernt (und markiert), wenn sie zwischen unzusammenhängendem Text schweben; der --strip-emoji-glue-Paranoid-Modus entfernt sie weiterhin überall
  • Emoji-/Skript-Politur: VS16 nach Emoji-Singletons außerhalb der Blockbereiche erhalten; Skript-Joiner, Flaggen-Emoji und arabische Cf-Marken erhalten; mehrsprachiges Unicode während der Textbereinigung erhalten (#34)
  • rewrite_text.py --gumbel-key
    WATERMARKS_GUMBEL_KEY
    gumbel
    /capabilities
    /detect
  • Benchmarks: Multi-Scheme-MarkLLM-Text-Benchmark und -Detektion (#188) und ein reproduzierbares SynthID-Text-Entfernungs-Benchmark (#145); Standard-Varianten paraphrase:3; Report und CSV tragen Versuche pro Dokument (mean_attempts / att, attempts / evaluator / passed-Spalten); --rewrite-loops spiegelt --max-loops
  • Detektion: Vendor-Text-Wasserzeichen-Erkennung (Gemini SynthID, Claude Seam, MarkLLM) plus ein SynthID-Bild-Scorer-Sidecar (#109); neuer Zero-LLM-statistischer und stylometrischer KI-Text-Detektor für CI und Audits (#68, #69)
  • --skill
    --list
    --link
    CLAUDE_CONFIG_DIR
    cowork
    dist/<skill>.zip
    make
    install-claude-code-skill
    install-claude-code-text-skill
    install-claude-project-skill
    package-cowork-skill
    package-cowork-text-skill
  • Deterministische Auto-Bereinigung über einen PostToolUse-Hook (hooks/hooks.json + service/scripts/hook_written_file.py): nachdem der Agent eine Datei schreibt, führt das Harness den Hook aus, unabhängig davon, ob das Modell kooperiert. check (Standard) meldet Marken an das Modell; clean entfernt sie in-place und teilt dem Modell mit, dass die Datei verschoben wurde, wobei nur bei einer echten Differenz getauscht wird, sodass saubere Dateien ihre mtime behalten. Der Modus kommt aus der hook_mode-Einstellung des Plugins oder WATERMARKS_HOOK_MODE; die Erkennung verwendet audit_lib.scan_file / is_actionable wieder, sodass der Hook, das Pre-Commit-Gate und der CI-SARIF-Export übereinstimmen. Ein Hook kann die Chat-Nachricht des Assistenten weiterhin nicht umschreiben — ein solcher Hook-Punkt existiert nicht —, sodass dieser Pfad Best-Effort bleibt
  • Pre-Commit-Hook-Integration für Staged-File-Prüfung/-Bereinigung (#138); leichtgewichtiger Cursor-Text-Skill (#35); die Beschreibung von clean-user-facing-text nennt Cursor nicht mehr als einzigen Host
  • service/Dockerfile
  • Docker / Compose: compose.yaml bringt die gesamte Infrastruktur hoch (core immer; markllm / markdiffusion hinter profile: harness; ctrlregen / synthid hinter profile: heavy als Local-Only-Builds); Dienste sind mit wr- präfixiert; Harness-/Heavy-Dienste verwenden standardmäßig command: ["--help"], sodass docker compose up --profile harness --profile heavy sauber beendet wird (One-Shot-CLIs werden mit docker compose run ausgeführt); neues make compose-check / compose-check.sh validiert den laufenden Stack (nur Exit-Code)
  • GHCR-Publishing: .github/workflows/release-images.yml veröffentlicht core-, markllm-, markdiffusion-Images bei v*-Tags; ctrlregen / synthid werden nie veröffentlicht (Upstream-Lizenzierung)
  • Env-Konfiguration: .env.example + Service-Konfigurationsanleitung; docker compose lädt .env automatisch; .env ist gitignored (Deny-by-Default)
  • Repo-Hygiene: .gitignore und service/.dockerignore sind jetzt Deny-by-Default — nur explizit erlaubte Pfade können committet oder in einen Build-Kontext gesendet werden (Image-Kontexte liefern nur service/scripts/, was alles ist, was die Dockerfiles COPYen)
  • Tests: tests/test_http_server.py (13 Fälle) für den HTTP-Dienst; alle Suiten auf service/scripts/ umgestellt
  • smoke-markdiffusion
    docker-markdiffusion-build
    docker-markdiffusion-help
  • Mock-basierte Tests (tests/test_markdiffusion_harness.py) — kein torch in CI; references/markdiffusion.md-Referenzdokument
  • Doku: Same-Scheme-Only-Verifikations-Caveat (kein Vendor-Detector-Oracle) und Blind-Regeneration-Drift-Caveat in README, SKILL.md, removal-matrix.md, markdiffusion.md
  • docker-markllm-help
  • Härtung: --offline Cache-Only-Modell-Loading (kein HF-Egress, kein Remote-Code), 1-MiB-Config-Cap, optionales WATERMARKS_MARKLLM_RLIMIT_AS auf dem Rewrite-Subprozess, gepinntes torch im Dockerfile und Clone-SHA-Verifikation in Dockerfile.markllm
  • Mock-basierte Tests (tests/test_markllm_detect.py, 21 Fälle) — kein torch in CI; Verifikations-Harness-Caveat (Same-Config-Only, kein Vendor-Detector-Oracle) dokumentiert in README, SKILL.md, removal-matrix.md, vendor-notes.md
  • Dockerfile.markdiffusion
    common.py
    /app
  • WebP: stdlib-only Inspektion und Metadaten-Bereinigung für RIFF-C2PA-, XMP-, EXIF- und ICC-Profil-Chunks (#37)
  • BMP / GIF / TIFF: stdlib-only Erkennung, Inspektion und Metadaten-Bereinigung — GIF-Kommentar-/XMP-Erweiterungen werden entfernt, während NETSCAPE2.0-Looping erhalten bleibt; TIFF-IFD-Metadaten (XMP/EXIF/GPS/IPTC/MakerNote) werden entfernt, Payloads genullt und Strip-Offsets beibehalten, sowohl für klassisches TIFF als auch BigTIFF; BMP-Trailing-Metadaten werden abgeschnitten und das Dateigrößen-Feld neu geschrieben
  • EPUB: stdlib-only Container-Bereinigung — OPF-Metadaten und XHTML-Meta/JSON-LD gescrubbt, eingebettete Raster-/SVG-Medien entfernt, Layer A auf XHTML-Body-Text angewendet, marker-tragende Metadaten-Teile verworfen und OCF-verschlüsselte Teile unangetastet durchgereicht
  • Dateinamen-Bereinigung: HTTP-Service verweigert unsichere, vom Client gelieferte Ausgabenamen
  • Markdown-Frontmatter-Cleaner repariert, der bei verschachtelten AI-Keys abstürzte und sie leaken ließ (#25)
  • Text-Tools verweigern Binär-Input; --force-text überschreibt (#24)
  • --json unterdrückt nicht mehr den Exit-Code für Residual-Signal (#30)
  • inspect_file gibt den Dateinamen aus (#50)
  • Mixed-Case-CMS-Generator-Meta-Tags beibehalten (#42)
  • Load-bearing Script-Invisibles beibehalten, PUA entfernen in Layer A (#38, #52)
  • Script-Joiner, Flaggen-Emoji und arabische Cf-Marks beibehalten in Layer A (#28)
  • Website-Audit gegen SSRF und Gzip-Bomben gehärtet (#49)
  • SECURITY.md verweist nur auf den privaten Advisories-Kanal (#51)
  • Windows: PowerShell-Ports der Setup-Bootstraps (#40)
  • Docs: Stars/Forks-Shields hinzugefügt und Star-History-Chart entfernt; MarkLLM zu README-Referenzen hinzugefügt; Pull-Request-Template; Plan für Docker CLI + API-Deployment
  • CtrlRegenEngine
    RLIMIT_FSIZE
  • Supply Chain: CI-Actions SHA-gepinnt mit permissions: contents: read, gepinnte Dev-Deps (requirements-dev.txt), ein pip-audit-Schritt und ein neuer CodeQL-Workflow; das Docker-Image läuft jetzt als unprivilegierter User mit gepinntem pip
  • Scorer-Deps: Pillow von 10.4.0 → 12.3.0 gebumpt (24 bekannte CVEs); API-Nutzung gegen den gepinnten Upstream-Commit verifiziert
  • Tests: 18 neue Security-Regressionstests (60 insgesamt, alle bestehen)
  • Tests für den Scorer-Adapter, CLI-Unavailable-Pfad, JSON-Parsing und Laufzeitfehler
  • Docs: nur Detection/Scoring (keine Pixel-Entfernung); Upstream-Code wird nicht gebündelt und bleibt unter seiner nicht-kommerziellen Research License
  • google-deepmind/synthid-text (Research-Referenz; hier nicht zur Detection verwendet)
  • aloshdenny/reverse-SynthID (Research-Referenz)
  • ETH Zurich SRI, Probing SynthID (Research-Blog zur Erkennbarkeit von SynthID-Wasserzeichen)
  • Liu et al., Image Watermarks are Removable Using Controllable Regeneration from Clean Noise (ICLR 2025) — die Pixel-Regenerations-Methode, die das optionale CtrlRegen-Backend implementiert — Code
  • Kassis & Hengartner, UnMarker: A Universal Attack on Defensive Image Watermarking (arXiv:2405.08363; IEEE S&P 2025) — ein universeller Wasserzeichen-Angriff, verglichen auf einer anderen Metrik als CtrlRegen
  • Goonatilake & Ateniese, Removing the Watermark Is Not Enough: Forensic Stealth in Generative-AI Watermark Removal (arXiv:2605.09203) — motiviert den konservativen Intensitäts-Standard: Entfernung kann dennoch forensische Spuren hinterlassen
  • mertizci/noai-watermark (CLI/Python-Toolkit für SynthID/StableSignature/TreeRing-Entfernung und AI-Metadaten-Stripping)
  • 0xROOTPLS/DeSynth (SynthID-Entfernung für OpenAI/Google-Bilder)
  • Institute of AI PM, AI Content Provenance and Watermarking: The PM's Guide to C2PA and SynthID (Zwei-Schichten-Branchenmodell: C2PA + imperzeptibles Wasserzeichen / Soft Binding; SB 942 / EU AI Act Art. 50-Kontext)