
Research-only AI watermark robustness toolkit: local reverse proxy strips C2PA/EXIF/XMP, Unicode, image/audio stego, OOXML/PDF metadata, and scans Trojan Source.
Universal AI Provenance & Watermark Sanitization Middleware Research artifact โ for watermarking robustness evaluation only.
NullOrigin is a research artifact. It is published to support academic and independent study of watermarking robustness, and for no other purpose.
Watermarking schemes are security claims, and security claims are only meaningful once someone has tried to break them. The literature this project implements โ Kirchenbauer et al. on KGW, Krishna et al. on paraphrase attacks, Boucher & Anderson on Trojan Source โ exists because researchers published working attacks so that defenders could measure real robustness instead of assuming it. That is the tradition this repository belongs to.
Intended uses
Not intended, and not supported
Nothing here is a technical control on how the code runs. It is a statement of the terms on which it is offered, and of what its author will and will not support. The software is provided "AS IS", without warranty of any kind โ see LICENSE.
Read Scope and honest limitations before drawing any conclusion from a number this tool prints. Several of the schemes it targets cannot be verified against a public detector, and the README says so rather than implying otherwise.
Read this before drawing conclusions from any number this tool prints.
| Layer | What it actually does |
|---|---|
| Invisible characters | Fully effective. Zero-width, bidi-control, variation-selector, and Unicode Tags-block payloads are removed completely, with a count reported. Cross-script homoglyph confusables (Cyrillic/Greek rendering as ASCII) are folded. |
| Document metadata (.docx) | Fully effective. Author, last editor, revision count, timestamps, template, and application version are cleared from docProps, with formatting preserved byte-for-byte. |
| C2PA / EXIF / XMP | Fully effective. The image is rebuilt from raw pixel samples into a fresh container, so signed JUMBF manifests and all metadata are gone. Verified by test against tagged fixtures. |
| KGW statistical watermark | Depends entirely on the rewrite backend. With no local model configured, the statistical watermark survives โ the tool says so rather than implying otherwise. |
| SynthID-Text / SynthID-Image / Tree-Ring | Not verifiable here. These use private keys and proprietary decoders. NullOrigin applies the perturbations the literature describes, but no claim is made that they defeat the real detectors, because there is no public detector to measure against. |
| AudioSeal / SynthID-Audio | Not verifiable here, for the same reason. |
KGWStatisticalDetector is a mathematically faithful, self-consistent implementation
of the Kirchenbauer et al. green/red-list scheme over whitespace tokens. It is not a
decoder for any vendor's production watermark โ those key on a private secret and the
model's own BPE vocabulary.
Its purpose is to make the benchmark real: KGWWatermarkEmbedder plants a genuine
watermark, the pipeline attacks it, and the matching detector measures the actual
reduction. That is a true measurement of the attack against this scheme. It does not
transfer to a vendor's watermark.
The vocabulary $V$ is partitioned at each step $t$ by a hash seeded on the preceding context:
$$s_t = \text{Hash}(w_{t-k}, \dots, w_{t-1})$$
into a green list $G_t$ of size $\gamma|V|$ and a red list $R_t$. A bias $\delta > 0$ is added to green logits:
$$\tilde{l}{t,v} = \begin{cases} l{t,v} + \delta, & v \in G_t \\ l_{t,v}, & v \in R_t \end{cases}$$
Detection counts green hits. Under $H_0$ they are $\text{Binomial}(T, \gamma)$, so:
$$z = \frac{|S_G| - \gamma T}{\sqrt{T\gamma(1-\gamma)}}$$
with $z > 4.0$ ($p < 3\times10^{-5}$) flagged as synthetic.
Why paraphrasing attacks it: the watermark lives entirely in local n-gram transitions. Rewriting the surface form with an unwatermarked model reseeds every position. This is the standard robustness attack in the watermarking literature.
Why length matters: $z$ grows as $\sqrt{T}$. A 100-token passage at a 0.70 green fraction only reaches $z \approx 3.9$ โ under threshold. Detection needs a few hundred tokens, and so do meaningful benchmark fixtures.
APP11 segments, PNG tEXt/iTXt chunks,
or WebP/AVIF c2pa boxes. Because the signature covers the pixel data, re-encoding
from a bare sample buffer removes it without parsing JUMBF at all.Sub-threshold phase modulation and low-amplitude spectral additions. Attacked by phase randomization above the speech fundamental, band-stop notch shifting in non-critical bands, and psychoacoustic re-quantization.
| Python | 3.10, 3.11, or 3.12 |
| OS | Linux, macOS (Intel and Apple Silicon), Windows via WSL2 |
| Optional | Ollama or any OpenAI-compatible server โ required for text de-watermarking |
| Optional | Docker 20.10+ with Compose v2 |
git clone https://github.com/rakib-nyc/nullorigin.git
cd nullorigin