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
nullorigin — Nur für Forschungszwecke gedachtes Toolkit zur Robustheit von KI-Wasserzeichen: lokaler Reverse-Proxy entfernt C2PA/EXIF/XMP, Unicode, Bild-/Audio-Steganografie, OOXML/PDF-Metadaten und scannt nach Trojan Source. | Kitploit
Tools/GitHubGitHub/rakib-nyc/nullorigin
Statische Code-Analyse (SAST)Web-Proxys & AbfangenSteganografiePrivatsphäreLernen & BildungKI-SicherheitAdversarial-Angriff
GitHubrakib-nyc/nullorigin

nullorigin

Nur für Forschungszwecke gedachtes Toolkit zur Robustheit von KI-Wasserzeichen: lokaler Reverse-Proxy entfernt C2PA/EXIF/XMP, Unicode, Bild-/Audio-Steganografie, OOXML/PDF-Metadaten und scannt nach Trojan Source.

Repository anzeigen
4vor 3 TagenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

NullOrigin 🛡️

Universelle Middleware für KI-Herkunftsnachweis & Wasserzeichen-Sanitisierung Forschungsartefakt — nur zur Bewertung der Robustheit von Wasserzeichen.

CI License: Apache 2.0 Python 3.10+ Tests Code style: ruff


🔬 Nur für Forschungszwecke

NullOrigin ist ein Forschungsartefakt. Es wird veröffentlicht, um die akademische und unabhängige Untersuchung der Robustheit von Wasserzeichen zu unterstützen – und für keinen anderen Zweck.

Wasserzeichenschemata sind Sicherheitsaussagen, und Sicherheitsaussagen sind nur dann aussagekräftig, wenn jemand versucht hat, sie zu brechen. Die Literatur, die dieses Projekt umsetzt — Kirchenbauer et al. zu KGW, Krishna et al. zu Paraphrasierungsangriffen, Boucher & Anderson zu Trojan Source — existiert, weil Forscher funktionierende Angriffe veröffentlicht haben, damit Verteidiger echte Robustheit messen können, statt sie anzunehmen. Das ist die Tradition, zu der dieses Repository gehört.

Beabsichtigte Verwendungen

  • Messen, wie stark die Erkennbarkeit eines Wasserzeichens unter einem angegebenen Angriff abnimmt
  • Reproduzieren und Erweitern veröffentlichter Robustheitsergebnisse
  • Bewerten von Herkunfts-Metadaten-Leaks in eigenen Dokumenten, bevor man sie teilt
  • Auditieren von Quellcode auf Trojan-Source- und Homoglyph-Angriffe (CVE-2021-42574, CVE-2021-42694)
  • Lehren, wie diese Schemata funktionieren und wo sie standhalten

Nicht beabsichtigt und nicht unterstützt

  • Generierte Arbeit als eigene auszugeben, wenn eine Person oder Institution darum gebeten hat, dies nicht zu tun
  • Herkunftssignale bei Inhalten zu umgehen, die man falsch darstellen will
  • Namensnennung von Arbeiten zu entfernen, die einem nicht gehören
  • Umgehung von Plattform-, Lizenz- oder akademischen Integritätsrichtlinien

Nichts davon ist eine technische Kontrolle darüber, wie der Code ausgeführt wird. Es ist eine Erklärung der Bedingungen, zu denen er angeboten wird, und dessen, was sein Autor unterstützen wird und was nicht. Die Software wird "WIE BESEHEN", ohne jegliche Gewährleistung bereitgestellt — siehe LICENSE.

Lies Umfang und ehrliche Grenzen, bevor du irgendeine Schlussfolgerung aus einer Zahl ziehst, die dieses Tool ausgibt. Mehrere der angegriffenen Schemata können nicht gegen einen öffentlichen Detektor verifiziert werden, und die README sagt dies deutlich, statt etwas anderes zu suggerieren.


Inhaltsverzeichnis

  • Nur für Forschungszwecke
  • Umfang und ehrliche Grenzen
  • Theoretische Grundlagen
  • Installation
  • Schnellstart
  • Docker
  • Bereitstellung über localhost hinaus
  • CLI
  • Benchmarking
  • Semantische Treue
  • Konfiguration
  • Fehlerbehebung
  • Architektur
  • Tests
  • Zitieren und Wiederverwendung
  • Projektstatus
  • Referenzen
  • Rechtlicher Hinweis & Namensnennung

⚠️ Umfang und ehrliche Grenzen

Lies dies, bevor du Schlussfolgerungen aus irgendeiner Zahl ziehst, die dieses Tool ausgibt.

Über den KGW-Detektor

KGWStatisticalDetector ist eine mathematisch getreue, selbstkonsistente Implementierung des Grün/Rot-Listen-Schemas von Kirchenbauer et al. über Whitespace-Token. Es ist kein Dekoder für produktive Wasserzeichen eines Anbieters — diese basieren auf einem privaten Geheimnis und dem eigenen BPE-Vokabular des Modells.

Sein Zweck ist es, das Benchmark real zu machen: KGWWatermarkEmbedder pflanzt ein echtes Wasserzeichen ein, die Pipeline greift es an, und der passende Detektor misst die tatsächliche Reduktion. Das ist eine echte Messung des Angriffs gegen dieses Schema. Es überträgt sich nicht auf ein Anbieter-Wasserzeichen.


📖 Theoretische Grundlagen

Text — KGW-Grün/Rot-Liste

Der Wortschatz $V$ wird bei jedem Schritt $t$ durch einen Hash partitioniert, der mit dem vorhergehenden Kontext gespeist wird:

$$s_t = \text{Hash}(w_{t-k}, \dots, w_{t-1})$$

in eine grüne Liste $G_t$ der Größe $\gamma|V|$ und eine rote Liste $R_t$. Ein Bias $\delta > 0$ wird zu den grünen Logits addiert:

$$\tilde{l}{t,v} = \begin{cases} l{t,v} + \delta, & v \in G_t \\ l_{t,v}, & v \in R_t \end{cases}$$

Die Erkennung zählt grüne Treffer. Unter $H_0$ sind sie $\text{Binomial}(T, \gamma)$, also:

$$z = \frac{|S_G| - \gamma T}{\sqrt{T\gamma(1-\gamma)}}$$

mit $z > 4.0$ ($p < 3\times10^{-5}$) wird als synthetisch markiert.

Warum Paraphrasierung es angreift: Das Wasserzeichen lebt vollständig in lokalen N-Gramm-Übergängen. Das Umschreiben der Oberflächenform mit einem nicht wasserzeichenmarkierten Modell setzt jede Position neu. Das ist der Standard-Robustheitsangriff in der Wasserzeichenliteratur.

Warum die Länge wichtig ist: $z$ wächst mit $\sqrt{T}$. Eine Passage mit 100 Token bei einem Grünanteil von 0,70 erreicht nur $z \approx 3.9$ — unter dem Schwellenwert. Die Erkennung braucht ein paar hundert Token, und aussagekräftige Benchmark-Fixtures ebenfalls.

Bild — C2PA und Frequenzbereich-Einbettung

  • C2PA / JUMBF: signierte Manifeste in JPEG-APP11-Segmenten, PNG-tEXt/iTXt-Chunks oder WebP/AVIF-c2pa-Boxen. Da die Signatur die Pixeldaten abdeckt, entfernt das erneute Kodieren aus einem rohen Sample-Puffer sie, ohne JUMBF überhaupt zu parsen.
  • SynthID-Image: Verschiebungen in DCT/DWT-Koeffizienten. Angegriffen durch weiches Schwellen der hochfrequenten Detail-Subbänder.
  • Tree-Ring: ein kreissymmetrisches Muster im anfänglichen Diffusions-Latent, das als kohärente Struktur in der Fourier-Phase überlebt. Angegriffen durch Randomisieren der Phase in mittelfrequenten Ringen unter Beibehaltung der Magnitude — weshalb das Bild visuell identisch bleibt.

Audio — AudioSeal / SynthID-Audio

Unterschwellige Phasenmodulation und Spektraladditionen mit geringer Amplitude. Angegriffen durch Phasenrandomisierung oberhalb der Sprachgrundfrequenz, Band-Sperr-Kerbverschiebung in nicht kritischen Bändern und psychoakustischer Re-Quantisierung.


📦 Installation

Anforderungen

Python3.10, 3.11 oder 3.12
OSLinux, macOS (Intel und Apple Silicon), Windows über WSL2
OptionalOllama oder ein beliebiger OpenAI-kompatibler Server —

Aus dem Quellcode```bash

git clone https://github.com/rakib-nyc/nullorigin.git cd nullorigin

python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate

pip install -e .

root@kitploit:~
### Optionale Extras```bash
pip install -e ".[dev]"       # pytest, pytest-asyncio, ruff  — needed to run the tests
pip install -e ".[nli]"       # torch + sentence-transformers, for the fidelity gate
pip install -e ".[metrics]"   # torch, transformers, sentence-transformers
pip install -e ".[llama]"     # llama-cpp-python for in-process GGUF inference
pip install -e ".[dev,metrics]"

Ohne [nli] läuft das Fidelity-Gate nur mit Invarianten – immer noch ein echter Check, aber blind für Rollentausch. Siehe Semantische Fidelity.

Installation überprüfen```bash

nullorigin --version nullorigin --help pytest -q # requires the [dev] extra

root@kitploit:~
---

## 🚀 Schnellstart

### 1. Ein lokales Rewrite-Modell einrichten

Das Entfernen von Wasserzeichen aus Text benötigt ein lokales Modell ohne Wasserzeichen. Ohne ein solches entfernt NullOrigin unsichtbare Zeichen, lässt aber **das statistische Wasserzeichen intakt** — und weist darauf hin.```bash
ollama serve                    # in a separate terminal
ollama pull llama3.2:3b         # or any instruct model you prefer

Verwenden Sie ein anderes Modell? Richten Sie NullOrigin darauf:```bash export NULLORIGIN_PARAPHRASER_MODEL=qwen3:4b export NULLORIGIN_PARAPHRASER_TIMEOUT=900 # reasoning models are slow

root@kitploit:~
### 2. Starten Sie den Proxy```bash
nullorigin run

Please provide the Markdown content to translate.```console NullOrigin 1.0.0 — proxy listening on 127.0.0.1:8080 providers: anthropic, gemini, openai text engine: unicode=True backend=ollama media: metadata=True stego=True telemetry: open (loopback) health: http://127.0.0.1:8080/health

root@kitploit:~
### 3. Richten Sie Ihren Client darauf aus```python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8080/v1", api_key="your-upstream-api-key")

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Write an essay about privacy."}],
    extra_headers={"x-nullorigin-provider": "openai"},
)
print(response.choices[0].message.content)

Anthropic:```python from anthropic import Anthropic

client = Anthropic(base_url="http://localhost:8080", api_key="your-upstream-api-key") message = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, messages=[{"role": "user", "content": "Write an essay about privacy."}], extra_headers={"x-nullorigin-provider": "anthropic"}, )

root@kitploit:~
curl:```bash
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "x-nullorigin-provider: openai" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"Hello"}]}'

Streaming (SSE) und Gemini (/v1beta/models/...) werden auf dieselbe Weise behandelt. Der x-nullorigin-provider-Header wählt den Upstream aus und wird vor der Weiterleitung entfernt; deine Auth-Header werden unverändert durchgereicht.


🐳 Docker```bash

git clone https://github.com/rakib-nyc/nullorigin.git cd nullorigin

docker compose up -d docker compose exec ollama ollama pull llama3.2:3b # first run only curl http://localhost:8080/health

root@kitploit:~
Der Compose-Stack betreibt NullOrigin plus einen Ollama-Sidecar in einem privaten Bridge-Netzwerk.
Der Proxy-Container bindet `0.0.0.0` — innerhalb eines Containers korrekt — und nur Port 8080 wird auf Ihren Host veröffentlicht.

Standalone-Image:```bash
docker build -t nullorigin:1.0.0 .
docker run -d -p 8080:8080 \
  -e NULLORIGIN_PARAPHRASER_BACKEND=none \
  nullorigin:1.0.0

Nützliche Befehle:```bash docker compose logs -f nullorigin docker compose down # stop docker compose down -v # stop and delete the Ollama model volume

root@kitploit:~
---

## 🔒 Bereitstellung außerhalb von localhost

**NullOrigin verwendet standardmäßig `127.0.0.1` und weigert sich, eine öffentliche Schnittstelle ohne
Telemetrie-Token zu binden.** Es leitet die Anmeldeinformationen deiner Upstream-API weiter, daher ist dies beabsichtigt:```console
$ nullorigin run --host 0.0.0.0
Error: Refusing to bind 0.0.0.0 without a telemetry token.

Choose one:
  - bind loopback:    nullorigin run --host 127.0.0.1
  - set a token:      export NULLORIGIN_TELEMETRY_TOKEN=$(openssl rand -hex 32)
  - accept the risk:  nullorigin run --host 0.0.0.0 --allow-public-bind

Um es richtig zu exponieren:```bash export NULLORIGIN_TELEMETRY_TOKEN=$(openssl rand -hex 32) nullorigin run --host 0.0.0.0 --port 8080

root@kitploit:~
then put it behind nginx, Caddy, or Traefik providing **TLS termination**, **Rate-
Limiting** und einer **Auth-Ebene**.

### Bedrohungsmodell

NullOrigin ist ein **lokaler Reverse-Proxy, der Ihre Upstream-API-Anmeldedaten weiterleitet**. Genau
diese Tatsache bestimmt seine Sicherheitshaltung.

| Kontrolle | Standard | Warum |
| --- | --- | --- |
| Bind-Adresse | `127.0.0.1` | Nur Loopback; eine öffentliche Bindung wird verweigert, sofern kein Telemetrie-Token gesetzt ist oder `--allow-public-bind` übergeben wird. |
| `/telemetry`, `/telemetry/reset` | Auf Loopback offen | Geschützt durch `X-NullOrigin-Token`, zeitkonstant verglichen, sofern `proxy.telemetry_token` gesetzt ist. |
| `/health` | Immer offen | Container-Probes benötigen ihn; zeigt Version und aktivierte Engines, keine Geheimnisse. |
| Anfrage-Body-Größe | 100 MiB | Der Proxy puffert Bodies, um sie weiterzuleiten; größere Eingaben werden mit `413` abgelehnt. |
| SSE-Puffer | 1 MiB | Ein Upstream, der einen Frame nie abschließt, wird geflusht, nicht unbegrenzt gepuffert. |
| Container-Benutzer | Nicht-Root | Der Proxy benötigt keine erhöhten Privilegien. |

Bekannte Einschränkungen, gewollt und keine Fehler:

* **Kein TLS.** Es leitet `Authorization` und `x-api-key` unverändert über unverschlüsseltes HTTP weiter. Platziere
  es hinter einem Reverse-Proxy, der HTTPS auf jedem nicht vertrauenswürdigen Netzwerk terminiert.
* **Keine Authentifizierung auf dem Proxy-Pfad.** Jeder, der den Port erreichen kann, kann darüber
  proxen und dabei eigene Anmeldedaten verwenden — NullOrigin speichert weder Schlüssel noch injiziert welche.
* **Kein Rate-Limiting.** Wende es am Reverse-Proxy an.
* **Anmeldedaten werden nie gespeichert.** Es wird kein API-Schlüssel auf der Festplatte oder in Logs geschrieben; Telemetrie
  zählt nur Anfragen und Bereinigungsereignisse.
* Die TLS-Prüfung des Upstreams bleibt aktiviert, und Weiterleitungen werden nicht verfolgt.

Um ein Sicherheitsproblem zu melden, sende eine E-Mail an **[email protected]** mit `[NullOrigin Security]` in
der Betreffzeile.

Telemetrie mit gesetztem Token:```bash
curl -H "X-NullOrigin-Token: $NULLORIGIN_TELEMETRY_TOKEN" http://localhost:8080/telemetry

/health ist niemals abgesichert, sodass Container-Probes weiterhin funktionieren.


🛠️ CLI```bash

nullorigin run [--host H] [--port P] [--config FILE] [--allow-public-bind] nullorigin purge INPUT -o OUTPUT [--verify] [--no-paraphrase] [--flatten-typography] nullorigin inspect INPUT [--json] nullorigin benchmark [--section text|media|audio] [-o report.json] nullorigin build-datasets [--root DIR] nullorigin test [pytest args...]

root@kitploit:~
### Unterstützte Formate

| Art | Erweiterungen | Anmerkungen |
| --- | --- | --- |
| **Bilder** | `.png` `.jpg` `.jpeg` `.jfif` `.webp` `.tif` `.tiff` `.bmp` `.gif` `.ico` `.avif` `.jp2` | Alle PIL-Modi (RGB, RGBA, L, LA, P, 1, I;16, CMYK, YCbCr). Animierte GIF/WebP und mehrseitige TIFF behalten jedes Einzelbild und deren Timing. Bilder unter 64px behalten exakte Abmessungen. |
| **Audio** | `.wav` `.wave` | 8/16/32-Bit-Integer, 32-Bit-Float; Mono bis Multichannel; beliebige Abtastrate. Dateien der Länge null überstehen den Roundtrip. |
| **Dokumente** | `.docx` `.docm` `.dotx` `.pptx` `.pptm` `.xlsx` `.xlsm` | Alle drei OOXML-Dialekte. Textläufe werden über Textkörper, Kopfzeilen, Fußzeilen, Fußnoten, Endnoten und Shared Strings bereinigt; `docProps`-Metadaten werden gelöscht; jeder andere Teil wird bytegenau kopiert. |
| **PDF** | `.pdf` | `/Info`-Wörterbuch, XMP-Paket, eingebettete Anhänge und JavaScript werden entfernt; Seiten, Text und Geometrie bleiben erhalten. Passwortgeschützte Dateien werden abgelehnt. Siehe den Hinweis unten. |
| **Quellcode** | `.py` `.js` `.ts` `.go` `.rs` `.java` `.c` `.cpp` `.rb` `.php` `.sh` `.sql` + 50 weitere | Trojan-Source- und Homoglyphen-Scan. **Kein NFKC, keine Paraphrasierung** — siehe unten. |
| **Text** | alles andere Dekodierbare | UTF-8, UTF-8-BOM, UTF-16, UTF-32, CP1252, Latin-1 — automatisch erkannt und **in derselben Kodierung zurückgeschrieben**. |

Alles andere wird **mit konkreter Anleitung abgelehnt**, statt als UTF-8 gelesen und
beschädigt zu werden — `.mp3` verweist auf `ffmpeg -i in.mp3 out.wav`, veraltete
`.doc`/`.ppt`/`.xls` auf das erneute Speichern als OOXML. Eine abgelehnte Datei erzeugt
niemals eine Ausgabe.

Verifiziert anhand eines Korpus aus 69 Dateien, das alle oben genannten Formate abdeckt: **59 korrekt verarbeitet,
10 sauber abgelehnt, null Abstürze, null beschädigte Ausgaben.**

### Code wird aus dem Umschreiber herausgehalten

Antworten des Assistenten mischen Prosa und Code in einem einzigen String. Übergibt man
das Ganze einem Paraphrasierungsmodell, wird der Code zusammen mit der Prosa
umgeschrieben — und der Z-Score sinkt in beiden Fällen, sodass nachgelagerte Prozesse
nichts bemerken.

Antworten werden daher segmentiert, bevor irgendetwas umgeschrieben wird:

| Segment | Behandlung |
| --- | --- |
| Prosa | Unicode-bereinigt, dann umgeschrieben |
| Umrandete Codeblöcke (``` und ~~~) | Unsichtbare und Bidi-Zeichen entfernt. **Kein NFKC, niemals umgeschrieben.** |
| Inline-`` `code` ``-Spannen | Gleich |

Das gilt auch auf dem Streaming-Pfad, wo sich eine Umrandung in einem Delta öffnet und
erst mehrere Deltas später schließt. Ein Delta, das die Grenze überspannt, wird pro
Zeile aufgeteilt, sodass das schließende ``` und die darauf folgende Prosa
unterschiedlich behandelt werden. Bei einer nicht geschlossenen Umrandung greift der
Fail-Safe: Der Rest wird geschützt statt umgeschrieben.

Deaktivieren mit `text.protect_code_blocks: false`, falls Sie das alte Verhalten wünschen.

### Quelldateien: ein Sicherheits-Scan, keine Wasserzeichenentfernung

**In KI-generiertem Quellcode gibt es kein Wasserzeichen.** Kein Anbieter markiert
Code-Ausgaben mit Wasserzeichen, und es existiert kein öffentlicher Detektor. Wer
behauptet, eines zu entfernen, verkauft Ihnen etwas.

Was Quellcode *sehr wohl* hat, ist eine reale, veröffentlichte Angriffsfläche:

* **Trojan Source** ([CVE-2021-42574](https://nvd.nist.gov/vuln/detail/CVE-2021-42574),
  Boucher & Anderson 2021) — bidirektionale Steuerzeichen ordnen neu, wie Code
  *angezeigt* wird, ohne zu ändern, wie er *kompiliert*. Ein Prüfer genehmigt ein
  Programm; der Compiler baut ein anderes.
* **Homoglyphen-Identifikatoren** ([CVE-2021-42694](https://nvd.nist.gov/vuln/detail/CVE-2021-42694))
  — kyrillisches `а` für lateinisches `a` erzeugt zwei Namen, die identisch gerendert werden.```console
$ nullorigin purge auth.py -o auth_clean.py --verify
Scanning source file auth.py...
  bidi controls removed:   4
  invisible chars removed: 0

  TROJAN SOURCE DETECTED (CVE-2021-42574): 4 bidirectional control character(s).
  This file rendered differently than it compiled. Review the diff.

Findings:
  CRITICAL line 3:25  U+202E RIGHT-TO-LEFT OVERRIDE — reorders displayed text
      if access_level != "user‮ ⁦// Check if admin⁩⁦":

Nach dem Bereinigen lautet die Zeile if access_level != "user // Check if admin": – der „Kommentar“ befand sich die ganze Zeit innerhalb des Strings.

Drei Dinge, die der Codepfad bewusst nicht tut, weil der generische Textpfad alle drei tat und jedes davon eine Fehlerquelle ist:

  1. Keine NFKC-Normalisierung. Sie schreibt String-Literal-Werte um: "Hello" wurde zu "Hello", "office" wurde zu "office". Das ändert, was ein Programm vergleicht, hasht und überträgt.
  2. Kein Umschreiben. Code an ein umschreibendes Modell zu senden, erzeugt Code, der nicht läuft.
  3. Homoglyphen werden gemeldet, nicht gefaltet. Das Falten eines kyrillischen а führt zwei Bezeichner zusammen, die der Compiler derzeit als unterschiedlich behandelt – und ändert damit stillschweigend das Verhalten. Der Schweregrad ist nur MEDIUM für gemischt-schriftliche Token (totаl), die eigentliche Angriffssignatur; ein Wort, das vollständig in einer anderen Schrift geschrieben ist, ist gewöhnlicher fremdsprachiger Text und erhält INFO. Aktivieren Sie es mit --fold-homoglyphs-in-code, sobald Sie sie überprüft haben.

inspect --json gibt pro Fund Schweregrad, Zeile, Spalte und Codepunkt aus und lässt sich so in CI als Pre-Commit- oder PR-Gate einbinden.

PDF: was entfernt wird und was nicht

Entfernt, nachweislich: das /Info-Wörterbuch (Author, Title, Subject, Keywords, Creator, Producer, CreationDate, ModDate), das XMP-Paket in /Root/Metadata, eingebettete Dateianhänge und JavaScript auf Dokumentebene. Seiten, Text und Seitengeometrie werden exakt beibehalten; der Vorgang ist idempotent und bytestabil.

Erkannt, aber NICHT entfernt: unsichtbare Zeichen in Seiteninhaltsströmen. PDF zeichnet Text Glyphe für Glyphe über eine schriftartspezifische Kodierung – ein Zero-Width-Leerzeichen in einer CID-keyed-Schrift ist ein Zwei-Byte-Glyphenindex, kein wörtliches U+200B – daher würde ein generisches Umschreiben das Layout beschädigen statt es zu bereinigen. inspect meldet die Anzahl; purge gibt eine Warnung aus, anstatt zu schweigen, denn Schweigen würde wie „es gab keine“ wirken. Um sie zu entfernen, extrahieren Sie den Text, führen Sie nullorigin purge darauf aus und erzeugen Sie die PDF neu.

--strip-annotations ist verfügbar, aber standardmäßig deaktiviert: Anmerkungen umfassen Links und Formularfelder, nicht nur Kommentare, daher ändert das Entfernen das Verhalten des Dokuments.

Typografie ist kein Wasserzeichen

Gedankenstriche, typografische Anführungszeichen und Ellipsen sind gewöhnliche Textverarbeitungsausgabe. NullOrigin behält sie standardmäßig bei und meldet sie getrennt von echten Befunden, da das Glätten ein Dokument verschlechtert, ohne etwas zu bereinigen. Verwenden Sie --flatten-typography, wenn Sie ausdrücklich ASCII-Ausgabe möchten.

Schriftübergreifende Verwechslungszeichen sind anders – ein kyrillisches о mitten im englischen Wort hat keine legitime Verwendung – und diese werden standardmäßig gefaltet.

--verify meldet Vorher/Nachher-Messwerte, anstatt Erfolg zu behaupten:```console $ nullorigin purge article.txt -o clean.txt --verify Cleaning text structure and token transitions in article.txt... removed 14 invisible characters, folded 3 homoglyphs applying semantic restructuring via ollama backend... restructuring complete Saved clean text to clean.txt

Verification (KGW statistical detector): z-score before: +5.3021 (p=5.73e-08) z-score after: +0.8874 (p=0.187) detected before/after (z>4.0): True -> False

root@kitploit:~
Wenn das Backend nicht erreichbar ist, wird dies als Warnung auf stderr gemeldet — ein stilles Fallback würde genauso aussehen wie eine erfolgreiche Bereinigung.

---

## 📊 Benchmarking```bash
nullorigin build-datasets
nullorigin benchmark

Jeder Wert wird direkt vor Ort gemessen: Text wird mit KGWWatermarkEmbedder mit einem Wasserzeichen versehen, durch die reale Pipeline geschickt und mit dem passenden Detektor erneut bewertet. Der Runner beendet sich mit einem Nicht-Null-Exitcode, wenn die Schwellenwerte nicht erreicht werden, und erklärt warum.

Schwellenwerte (aus der Projektanweisung):

MetrikZiel
Z-Score nach Sanitization$\lvert z\rvert \le 1.5$
Semantische Ähnlichkeit$\ge 0.92$
Bild-SSIM$\ge 0.95$
Bild-PSNR$\ge 36$ dB

Gemessene Ergebnisse

Vollständiger Textabschnitt über datasets/text/watermarked_kgw.json, neu geschrieben durch Ollama (qwen3:4b) auf einem MacBook der M-Serie (~150 s pro Passage):```text sample z_before z_after reduced detected kgw_000 4.212 -0.065 4.277 no kgw_001 5.297 0.484 4.813 no kgw_002 6.120 -0.482 6.601 no kgw_003 4.711 1.271 3.440 no kgw_004 5.696 0.209 5.486 no invisible_payload -0.447 1.091 -1.538 no

mean z: 4.2647 -> 0.4182 max |z| after: 1.271 (target: <= 1.5) still detected at z > 4.0: 0 of 5 invisible chars remaining: 0

pass_z_threshold: PASS pass_no_detection: PASS pass_unicode_purge: PASS OVERALL: PASS (3/3)

root@kitploit:~
Jede mit Wasserzeichen versehene Probe wechselte von erkannt zu unerkannt. Beachte `kgw_003` bei
z = 1.271 — unter dem Schwellenwert, aber am nächsten daran, was die ehrliche Form dieses
Angriffs ist: Er ist statistisch, keine Garantie.

Medien, gemessen über die Bildvorlagen:```text
sample                      ssim   psnr_dB  meta_clear
c2pa_tagged.png           0.9950     46.84         yes
exif_tagged.jpg           0.9690     40.54         yes
clean_control.png         0.9951     46.90         yes

Beide Bildschwellen sind erfüllt (SSIM ≥ 0.95, PSNR ≥ 36 dB). Die Zahlen variieren je nach Modell, Hardware und Textpassage.

Semantische Treue: Ein Z-Score-Abfall ist kein Beweis für erhaltene Bedeutung

Eine Umschreibung, die eine Tatsache verändert, schneidet bei der Wasserzeichen-Metrik genauso ab wie eine originalgetreue. Die offensichtliche Prüfung dafür funktioniert nicht, und die weniger offensichtliche auch nicht. Gemessen an sechs Driftfällen plus einer originalgetreuen Kontrolle:

Die lexikalische Überlappung ist invertiert. Jede bedeutungszerstörende Änderung schnitt höher ab als die originalgetreue Umschreibung, denn eine gute Paraphrase teilt nur wenige N-Gramme mit ihrer Quelle, während eine korrumpierte fast alle davon teilt.

Der Embedding-Cosinus behebt das nicht. Drei der sechs korrupten Fälle bestehen einen Schwellenwert von 0.92. "Alice paid Bob" und "Bob paid Alice" sind derselbe Bag of Words und erzielen 0.985; "must not disable" → "must disable" erzielt 0.947. Satz-Embeddings kodieren thematische Verwandtschaft, nicht Wahrheit.

Die Treue wird also in zwei Ebenen geprüft, und keine davon ist der Cosinus:

  1. Invarianten — Zahlen, Anzahl der Negationen, modale Stärke, Quantorstärke, URLs, E-Mails, Identifikatoren, benannte Entitäten. Deterministisch, ohne Abhängigkeiten und erklärbar (negation count changed: 1 → 0). Modalverben und Quantoren werden nach Bedeutungsklasse verglichen, sodass may → might besteht und may → must scheitert. Blind gegenüber Rollenvertauschungen, bei denen jede Entität überlebt.
  2. Bidirektionale Folgerung — Die Bedeutung bleibt genau dann erhalten, wenn jeder Text den anderen impliziert. Erfasst, was das Zählen nicht kann, einschließlich Rollenvertauschungen, und die Asymmetrie ist diagnostisch (Entfernen der Absicherung ergab a⇒b 0.991, b⇒a 0.011). Erfordert nullorigin[nli]; ohne dieses wird die Einschränkung gemeldet, nicht versteckt.

Es ist ein Gate, kein Bericht

Das Messen von Drift im Nachhinein hilft nicht, wenn der beschädigte Text bereits zurückgegeben wurde. Eine fehlgeschlagene Prüfung wiederholt bei einer niedrigeren Temperatur — Drift ist temperaturabhängig — und gibt nach dem Retry-Budget das Original zurück, mit ok=False und dem Grund.```yaml text: fidelity: enabled: true max_retries: 2 temperature_step: 0.25 use_nli: true nli_threshold: 0.5

root@kitploit:~
Das bedeutet auch, dass Angriff und Risiko an derselben Stellschraube hängen: Höhere Temperatur senkt den
z-Score *und* erhöht die Driftrate. Der Benchmark weist sie gemeinsam aus, statt als
unabhängige Prüfungen.

### Weitere Metriken

* **Perplexität** — echte GPT-2-PPL mit `torch` + `transformers`, andernfalls
  `unigram_entropy_proxy`, als Näherung gekennzeichnet und **nicht** mit veröffentlichter PPL vergleichbar.
* **Cosinus-Ähnlichkeit** wird weiterhin als `mean_cosine_or_lexical` berichtet, nur zur Referenz.
  Sie ist kein Bestehen/Nichtbestehen-Kriterium mehr, aus den Gründen in der obigen Tabelle.

## ⚙️ Konfiguration

Auflösungsreihenfolge, von niedrigster zu höchster Priorität:

1. Integrierte Standardwerte
2. `nullorigin.yaml` (gesucht in `./`, `../`, `/app/` oder `$NULLORIGIN_CONFIG`)
3. `NULLORIGIN_*`-Umgebungsvariablen
4. Explizite CLI-Flags

### Wichtige Einstellungen

| Einstellung | Standard | Anmerkungen |
| --- | --- | --- |
| `proxy.host` | `127.0.0.1` | Loopback. Eine öffentliche Bindung wird ohne Telemetrie-Token verweigert. |
| `proxy.port` | `8080` | |
| `proxy.default_provider` | `openai` | Verwendet, wenn kein `x-nullorigin-provider`-Header gesendet wird. |
| `proxy.telemetry_token` | `""` | Schützt `/telemetry` und `/telemetry/reset`. |
| `proxy.max_request_bytes` | `104857600` | 100 MiB; größere Anfragekörper erhalten `413`. |
| `text.paraphraser.backend` | `ollama` | `none` \| `ollama` \| `openai_compatible` \| `llama_cpp` \| `lexical`. `none` lässt das statistische Wasserzeichen intakt. `lexical` benötigt kein Modell, ist aber ein weitaus schwächerer Angriff. |
| `text.clean_unicode` | `true` | Entfernung von Zero-Width- und Tags-Block-Zeichen. |
| `text.fold_homoglyphs` | `true` | Kyrillische/griechische Homoglyphen zu ASCII. |
| `text.stream_window_tokens` | `40` | Deltas werden gepuffert, bevor ein Streaming-Abschnitt neu geschrieben wird. |
| `media.crop_mode` | `trim` | `trim` verschiebt Koordinaten ohne Resampling; `resample` stellt die exakten Abmessungen wieder her, kostet aber selbst bei einem 0.5%-Beschnitt grob SSIM 0.81 / PSNR 31 dB; `none` deaktiviert den geometrischen Durchlauf. |
| `audio.low_cut_hz` | `800.0` | Die Phase darunter bleibt für die Verständlichkeit erhalten. |

### Umgebungsvariablen```bash
NULLORIGIN_CONFIG                  # path to nullorigin.yaml
NULLORIGIN_HOST                    # bind address
NULLORIGIN_PORT
NULLORIGIN_TELEMETRY_TOKEN
NULLORIGIN_MAX_REQUEST_BYTES
NULLORIGIN_DEFAULT_PROVIDER
NULLORIGIN_PARAPHRASER_BACKEND     # none | ollama | openai_compatible | llama_cpp | lexical
NULLORIGIN_PARAPHRASER_ENDPOINT    # alias: NULLORIGIN_OLLAMA_ENDPOINT
NULLORIGIN_PARAPHRASER_MODEL
NULLORIGIN_PARAPHRASER_MODEL_PATH  # llama_cpp GGUF path
NULLORIGIN_PARAPHRASER_API_KEY
NULLORIGIN_PARAPHRASER_TIMEOUT
NULLORIGIN_PARAPHRASER_TEMPERATURE
NULLORIGIN_CLEAN_UNICODE
NULLORIGIN_FOLD_HOMOGLYPHS
NULLORIGIN_PURGE_METADATA
NULLORIGIN_DISRUPT_STEGO
NULLORIGIN_DISRUPT_AUDIO

🩺 Fehlerbehebung

model 'llama3.2:3b' not found Das konfigurierte Modell wurde nicht heruntergeladen. Führe ollama list aus, um zu sehen, was du hast, und führe dann entweder ollama pull llama3.2:3b aus oder setze NULLORIGIN_PARAPHRASER_MODEL auf ein Modell, das du bereits hast.

WARNING: ollama backend unavailable (ReadTimeout) Die Neuformulierung überschritt text.paraphraser.timeout_seconds (Standard 120 s). Reasoning-Modelle wie qwen3 benötigen auf der CPU regelmäßig 150 s+ pro Absatz. Erhöhe den Wert: export NULLORIGIN_PARAPHRASER_TIMEOUT=900, oder verwende ein kleineres Instruct-Modell.

nullorigin benchmark exits 1 with pass_no_detection: FAIL Funktioniert wie vorgesehen. Es war kein Rewrite-Backend erreichbar, sodass nur die Unicode-Ebene lief und das statistische Wasserzeichen überlebte. Starte Ollama oder setze das Backend für einen Vergleich ohne Abhängigkeiten auf lexical.

semantic_check: INCONCLUSIVE Ohne das [metrics]-Extra erwartet. Siehe Metric honesty.

Error: Refusing to bind 0.0.0.0 without a telemetry token Absichtlich. Siehe Deploying beyond localhost.

Multiple top-level packages discovered in a flat-layout Du hast einen alten Checkout. pyproject.toml definiert eine explizite Paketliste; hole den neuesten Stand.

Async tests report UsageError about a missing async plugin Absichtlich – ohne ein solches Plugin meldet pytest async def-Tests als bestanden, ohne sie abzuwarten. pip install -e ".[dev]".

Docker: curl: (7) Failed to connect right after compose up Der Healthcheck hat eine Startphase von 10 s. Warte und prüfe dann docker compose logs nullorigin.


🏗️ Architektur```text

root@kitploit:~
                Client / Application
                        |
          [http://localhost:8080/v1/...]
                        v
    +===================================================+
    |               NULLORIGIN CORE PROXY               |
    |  HTTP/SSE interceptor · provider schema adapter   |
    |  /health · /telemetry · transparent auth passthru |
    +===================================================+
                        |
          [request forwarded unmodified]
                        v
          Upstream Provider API (Anthropic / OpenAI / Gemini)
                        |
              [watermarked payload]
                        v
    +===================================================+
    |            SANITIZATION PIPELINE ROUTER           |
    +===================================================+
       /                 |                      \

(text/JSON+SSE) (image/*) (audio/wav) v v v +----------------+ +------------------+ +------------------+ | MODULE B: TEXT | | MODULE C: MEDIA | | MODULE D: AUDIO | | unicode purge | | C2PA/EXIF scrub | | phase randomize | | homoglyph fold | | DWT threshold | | notch shifting | | KGW detector | | Fourier phase | | psychoacoustic | | SLM rewriter | | dither | | requantization | +----------------+ +------------------+ +------------------+ \ | / +----------------+---------------------+ v Schema reconstruction (SSE framing preserved) v Sanitized stream / file

root@kitploit:~
### Layout```text
nullorigin/
├── cli.py                        # run, purge, inspect, benchmark, build-datasets, test
├── config.py                     # Pydantic v2 settings + env overrides
├── proxy/
│   ├── server.py                 # FastAPI reverse proxy, /health, /telemetry
│   ├── interceptors.py           # SSE frame parser + sliding-window rewriter
│   ├── telemetry.py              # thread-safe runtime counters
│   └── schemas.py                # provider request/response models
├── engines/
│   ├── text/
│   │   ├── unicode_cleaner.py    # invisible chars, Tags block, homoglyphs
│   │   ├── paraphraser.py        # pluggable rewrite backends
│   │   └── kgw_detector.py       # detector + Viterbi embedder
│   ├── media/
│   │   ├── c2pa_remover.py       # JUMBF/EXIF/XMP stripping + inspection
│   │   └── stego_breaker.py      # DWT thresholding, Fourier phase, dither
│   └── audio/
│       └── audio_cleaner.py      # phase randomization, notch shifting
└── evaluation/
    ├── metrics.py                # SSIM, PSNR, PPL, semantic similarity
    ├── datasets.py               # deterministic fixture generation
    └── runner.py                 # measured benchmark harness

🧪 Testen```bash

pytest -q

root@kitploit:~
384 Tests. Die Testsuite deckt den SSE-Frame-Parser bei adversarialen Chunk-Grenzen ab, den Proxy-Streaming-Lebenszyklus, jeden PIL-Bildmodus, SSIM sowohl gegen einen geschlossenen Formwert als auch gegen eine Brute-Force-Referenzimplementierung und die Erkennbarkeit von Wasserzeichen im Datensatz.

Async-Tests schlagen lautstark fehl, wenn kein Async-Plugin installiert ist, anstatt stillschweigend übersprungen zu werden.

---

## 📖 Zitieren und Weiterverwendung

Lizenziert unter Apache-2.0, was Nutzung, Modifikation und Weiterverbreitung gestattet, sofern der Urheberrechtshinweis und die Namensnennung von **Muhammad Rakibul Islam** erhalten bleiben. Siehe [LICENSE](https://github.com/rakib-nyc/nullorigin/blob/HEAD/LICENSE) und [NOTICE](https://github.com/rakib-nyc/nullorigin/blob/HEAD/NOTICE).

Wenn diese Arbeit eine Veröffentlichung unterstützt, zitieren Sie sie bitte wie folgt:```bibtex
@software{islam_nullorigin_2026,
  author  = {Islam, Muhammad Rakibul},
  title   = {{NullOrigin}: Universal AI Provenance and Watermark
             Sanitization Middleware},
  year    = {2026},
  version = {1.2.0},
  url     = {https://github.com/rakib-nyc/nullorigin},
  note    = {Research artifact for watermarking robustness evaluation}
}

Dieses Repository wird als fertiges Forschungsartefakt veröffentlicht und akzeptiert keine Pull-Requests. Du kannst es unter den Bedingungen der Lizenz gerne forken. Fragen und Erkenntnisse sind per E-Mail an [email protected] willkommen.


🗺️ Projektstatus

Version 1.0.0. Die Suite ist entsprechend ihrer Spezifikation vollständig und umfassend getestet, mit diesen bekannten Einschränkungen:

  • Die Wirksamkeit gegen SynthID, Tree-Ring und AudioSeal ist hier nicht verifizierbar — es existiert kein öffentlicher Detektor, um sie zu messen. Die Perturbationen sind implementiert; die Behauptung wird nicht aufgestellt.
  • Semantische Drift wird durch Invarianten plus optionales NLI begrenzt. Ohne [nli] sind Rollenwechsel, bei denen jede Entität erhalten bleibt, nicht erkennbar, und der Bericht sagt dies aus.
  • Die Latenz mit einem lokalen Reasoning-Modell (~150 s pro Passage) macht den Textpfad für den interaktiven Einsatz ungeeignet. Ein kleineres Instruct-Modell ist deutlich schneller.
  • Kein TLS und keine Request-Authentifizierung — bewusst so; betreibe es hinter einem Reverse-Proxy.

Siehe CHANGELOG.md für die Versionshistorie.


📚 Referenzen

  • Kirchenbauer et al., A Watermark for Large Language Models (2023) — das KGW-Schema
  • Dathathri et al., Scalable watermarking for identifying large language model outputs (Nature, 2024) — SynthID-Text
  • Wen et al., Tree-Rings Watermarks: Invisible Fingerprints for Diffusion Images (2023)
  • San Roman et al., Proactive Detection of Voice Cloning with Localized Watermarking (2024) — AudioSeal
  • Krishna et al., Paraphrasing evades detectors of AI-generated text (2023)
  • Wang et al., Image Quality Assessment: From Error Visibility to Structural Similarity (2004) — SSIM
  • C2PA Specification

📜 Rechtlicher Hinweis & Namensnennung

  • Autor & Ersteller: Muhammad Rakibul Islam
  • Kontakt: [email protected]
  • Lizenz: Apache License, Version 2.0

Dieses Repository ist ein forschungstaugliches Artefakt, das für statistische Forschung, Datenschutzbewertung, Robustheits-Benchmarking von Wasserzeichen und kryptografische Resilienztests veröffentlicht wurde.```text Copyright 2026 Muhammad Rakibul Islam [email protected]

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

root@kitploit:~
http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

root@kitploit:~
**KEINERLEI GEWÄHRLEISTUNG.** DIE SOFTWARE WIRD „WIE BESEHEN" BEREITGESTELLT, OHNE JEGLICHE GEWÄHRLEISTUNG,
AUSDRÜCKLICH ODER STILLSCHWEIGEND.
Tool herunterladen
SchichtWas es tatsächlich tut
Unsichtbare ZeichenVoll wirksam. Zero-Width-, Bidi-Steuer-, Varianten-Selektor- und Unicode-Tags-Block-Payloads werden vollständig entfernt, mit einem gemeldeten Zählerstand. Querschriftliche Homoglyph-Verwechslungen (Kyrillisch/Griechisch, die als ASCII erscheinen) werden gefaltet.
Dokumentmetadaten (.docx)Voll wirksam. Autor, letzter Bearbeiter, Revisionszähler, Zeitstempel, Vorlage und Anwendungsversion werden aus docProps entfernt, wobei die Formatierung bytegenau erhalten bleibt.
C2PA / EXIF / XMPVoll wirksam. Das Bild wird aus rohen Pixelproben in einen frischen Container neu aufgebaut, sodass signierte JUMBF-Manifeste und alle Metadaten verschwinden. Durch Tests gegen getaggte Fixtures verifiziert.
KGW-statistisches WasserzeichenHängt vollständig vom Rewrite-Backend ab. Ohne konfiguriertes lokales Modell überlebt das statistische Wasserzeichen — das Tool sagt dies deutlich, statt etwas anderes zu suggerieren.
SynthID-Text / SynthID-Image / Tree-RingHier nicht verifizierbar. Diese verwenden private Schlüssel und proprietäre Dekoder. NullOrigin wendet die in der Literatur beschriebenen Störungen an, aber es wird keine Behauptung aufgestellt, dass sie die echten Detektoren überwinden, weil es keinen öffentlichen Detektor gibt, gegen den gemessen werden könnte.
AudioSeal / SynthID-AudioHier nicht verifizierbar, aus demselben Grund.
erforderlich für die Text-Entwasserzeichenung
OptionalDocker 20.10+ mit Compose v2
Falllexical_f1Embedding-Cosinusbidirektionales NLI
Negation entfernt0.700.77 ✓0.000 ✓
Zahl 5 → 500.820.81 ✓0.000 ✓
Entitäts-/Rollenvertauschung0.810.985 ✗0.000 ✓
Quantor alle → einige0.880.91 ✓0.000 ✓
Absicherung entfernt0.270.953 ✗0.011 ✓
"must not" → "must"0.830.947 ✗0.000 ✓
originalgetreue Umschreibung0.330.931 ✓0.998 ✓