Skip to main content

dewatermark

Remove Unicode text watermarks and mitigate published statistical LLM watermarks with quality-constrained rewriting.

It does not claim to remove an Anthropic/Claude-specific watermark. Anthropic has not publicly documented a deployed Claude text-watermark scheme or detector. Unknown vendor systems, provider-side retrieval, and semantic provenance may remain detectable after rewriting.

Install

Install the latest development version directly from GitHub:

pip install "git+https://github.com/cyzanfar/dewatermark.git"

For published releases:

pip install dewatermark
pip install "dewatermark[local]"   # local self-information scorer + BIRA
pip install "dewatermark[eval]"    # evaluation models

Quickstart

import dewatermark

# Safe by default: removes unambiguous covert controls without folding valid
# emoji shaping, RTL controls, compatibility characters, or confusables.
clean = dewatermark.sanitize("he\u200bllo")
forensics = dewatermark.analyze(text)

result = dewatermark.remove(text, mode="auto")
print(result.cleaned_text)
print(result.report)

# Explicitly lossy Latin-text canonicalization:
canonical = dewatermark.sanitize(text, profile="aggressive")

Model downloads are also opt-in. Preload one explicitly with dewatermark download-model, or set allow_model_download=True when constructing a configuration.

Command line and agents

The CLI never prompts and supports stdin, stable JSON, JSONL batches, dry runs, and capability discovery:

printf 'he\u200bllo' | dewatermark sanitize --format json
dewatermark capabilities
dewatermark remove --mode auto --dry-run --format json
dewatermark remove --mode sanitize --format jsonl < requests.jsonl
dewatermark schema

Python callers can inspect dewatermark.capabilities() and dewatermark.plan(mode) without network access, model loading, or downloads. remove_many() preserves batch order and aremove() integrates with async agent runtimes. Results carry a versioned JSON schema with explicit status, backend, fallback, warnings, and stage details.

Remote processing is deny-by-default because source text may be sensitive:

from dewatermark import Dewatermark, DewatermarkConfig

dw = Dewatermark(DewatermarkConfig(
    lm_backend="fireworks",
    fireworks_api_key="fw-...",
    allow_remote_processing=True,
))
result = dw.remove(text, mode="bias_inversion", beta=6.0)

Removal modes

  • sanitize: Unicode cleanup only. safe is the default profile; aggressive enables lossy NFKC/confusable folding.
  • bias_inversion: BIRA-style surprisal proxy set, negative logit bias, adaptive bias backoff/restarts, and deterministic quality gates.
  • sira: proportional self-information masking, reference rewrite, targeted infill, and quality-gated acceptance.
  • paraphrase / full: structural and cross-lingual rewriting baselines.
  • adversarial: best-of-N SIRA candidates. Its surprisal score is a weak selection heuristic, not proof that a watermark was removed.
  • auto: BIRA first, quality/failure-aware fallback to paraphrasing, then sanitize-only when no rewrite backend is usable.

Long inputs are split at paragraph/sentence boundaries and reconstructed exactly at chunk boundaries. Local models use CUDA/MPS automatically when available. A 7B–14B instruction model is recommended for rewrite quality; the 0.5B default demonstrates the mechanism but should not be expected to reproduce published attack results.

Safety and quality behavior

Every generated candidate is rejected if it is empty, truncated/expanded past configured bounds, repetitive, contains mask placeholders, or drops numbers, URLs, email addresses, or quoted strings. These deterministic checks catch catastrophic failures but do not prove semantic equivalence; production users should add NLI, claim-QA, and human review for consequential content.

Important configuration:

Environment variable Default Purpose
DEWATERMARK_LM_BACKEND auto local, fireworks, or automatic selection
DEWATERMARK_LOCAL_LM Qwen/Qwen2.5-0.5B-Instruct Local scorer/rewriter
DEWATERMARK_ALLOW_MODEL_DOWNLOAD false Explicit model acquisition consent
DEWATERMARK_FIREWORKS_AI_API_KEY Fireworks scorer/rewriter
DEWATERMARK_LLM_API_KEY OpenAI-compatible paraphrase/SIRA endpoint
DEWATERMARK_ALLOW_REMOTE_PROCESSING false Consent to transmit source text
DEWATERMARK_SANITIZE_PROFILE safe safe or explicitly lossy aggressive
DEWATERMARK_MAX_CHUNK_CHARS 12000 Rewrite chunk bound
DEWATERMARK_MAX_INPUT_CHARS 1000000 Per-request input bound
DEWATERMARK_MAX_REMOTE_CALLS 16 Per-operation remote-call budget
DEWATERMARK_MAX_OUTPUT_TOKENS 2048 Generated-token budget
DEWATERMARK_MAX_CONCURRENCY 4 Batch worker bound
DEWATERMARK_REQUEST_TIMEOUT 120 Per-request timeout ceiling
DEWATERMARK_QUALITY_MIN_LENGTH_RATIO 0.70 Candidate acceptance bound
DEWATERMARK_QUALITY_MAX_LENGTH_RATIO 1.35 Candidate acceptance bound

Unprefixed v0.2 names remain compatibility aliases during the 0.3 release line.

Evaluation

The harness uses matched transformed nulls, refuses to estimate an empirical FPR without at least ceil(1/FPR) null samples, provides confidence intervals, and supports length sweeps. Independent official implementations can be connected through the JSON command-adapter contract in eval/adapters.py.

dewatermark-eval --skip-statistical --output results.md

# Expensive research run. 1e-5 FPR is deliberately reported as not estimable
# unless at least 100,000 matched nulls are supplied.
DEWATERMARK_ALLOW_REMOTE_PROCESSING=true dewatermark-eval \
  --samples 100 --null-samples 1000 \
  --lengths 100,250,500,1000,2000 \
  --modes bias_inversion,sira,full \
  --model-revision MODEL_COMMIT --allow-model-download \
  --json-output results.json --checkpoint progress.jsonl

The checked-in eval/RESULTS.md explains why no statistically valid v0.2 efficacy result is currently claimed. The runner uses strict failure handling by default and records configuration, package versions, hardware, prompt hashes, checkpoints, and machine-readable results.

Extending and contributing

Third-party scorers and rewriters can implement the structural interfaces in dewatermark.protocols, register in-process, or publish through the dewatermark.providers entry-point group. See extension documentation, architecture, and contributor guide.

Scope limitations

  • No public Claude-specific scheme is available to target or verify.
  • Retrieval-based provenance cannot be removed from text.
  • Token surprisal does not reliably identify semantic, post-processing, cryptographic, learned, or undisclosed watermarks.
  • Detector success must be stated for a named scheme, key/configuration, operating threshold, text length, and quality constraint—not as universal “watermark removal.”

License

The package code is MIT-licensed; see LICENSE. The generated confusables table incorporates Unicode data distributed under the Unicode License v3.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dewatermark-0.3.0.tar.gz (75.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dewatermark-0.3.0-py3-none-any.whl (76.3 kB view details)

Uploaded Python 3

File details

Details for the file dewatermark-0.3.0.tar.gz.

File metadata

  • Download URL: dewatermark-0.3.0.tar.gz
  • Upload date:
  • Size: 75.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for dewatermark-0.3.0.tar.gz
Algorithm Hash digest
SHA256 f7b42f3a17187561655259956dc9c20c2bba47d701d175be2a5ae69ac6d72769
MD5 33df5be2da6b4e8915da7c5f780ae992
BLAKE2b-256 04fbbb2be907c47cdde3caa9418a0a729d96a1353f26b3f0b17852cac2983c4e

See more details on using hashes here.

Provenance

The following attestation bundles were made for dewatermark-0.3.0.tar.gz:

Publisher: publish.yml on cyzanfar/dewatermark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dewatermark-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: dewatermark-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 76.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for dewatermark-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bd6b5848b79024ec9fe59309ae8be38f23b8ac3491097e4bb2b671c2e7493ab2
MD5 e1577685a730b462ec0c45671f88e6b6
BLAKE2b-256 6cc965b0ddce96cd194f727255fe71ff511429068feae69cc17012e7d339c51d

See more details on using hashes here.

Provenance

The following attestation bundles were made for dewatermark-0.3.0-py3-none-any.whl:

Publisher: publish.yml on cyzanfar/dewatermark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page