Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
nullorigin — 研究専用AIウォーターマーク堅牢性ツールキット:ローカルリバースプロキシがC2PA/EXIF/XMP、Unicode、画像/音声ステゴ、OOXML/PDFメタデータを除去し、Trojan Sourceをスキャンする。 | Kitploit
ツール/GitHubGitHub/rakib-nyc/nullorigin
静的コード分析 (SAST)ウェブプロキシと傍受ステガノグラフィープライバシー学習と教育AIセキュリティ敵対的攻撃
GitHubrakib-nyc/nullorigin

nullorigin

研究専用AIウォーターマーク堅牢性ツールキット:ローカルリバースプロキシがC2PA/EXIF/XMP、Unicode、画像/音声ステゴ、OOXML/PDFメタデータを除去し、Trojan Sourceをスキャンする。

リポジトリを見る
43日前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

NullOrigin 🛡️

ユニバーサルAI由来・透かしサニタイゼーションミドルウェア 研究用アーティファクト — 透かしロバスト性評価専用。

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


🔬 研究用のみ

NullOrigin は研究用アーティファクトです。透かしロバスト性に関する学術的・独立的な研究を支援するために公開されており、それ以外の目的はありません。

透かし方式はセキュリティ上の主張であり、セキュリティ上の主張は、誰かがそれを破ろうと試みて初めて意味を持ちます。このプロジェクトが実装する文献 — KGW に関する Kirchenbauer ら、パラフレーズ攻撃に関する Krishna ら、Trojan Source に関する Boucher & Anderson — は、研究者が実際に動作する攻撃を公開し、防御側が想定ではなく現実のロバスト性を測定できるようにしたからこそ存在します。このリポジトリが属するのは、そうした伝統です。

意図された用途

  • 明示された攻撃下で、透かしの検出可能性がどの程度低下するかを測定すること
  • 公表されたロバスト性評価結果の再現と拡張
  • 共有前に、自身の文書における来歴メタデータの漏えいを評価すること
  • ソースコードの Trojan Source およびホモグリフ攻撃(CVE-2021-42574、CVE-2021-42694)の監査
  • これらの方式がどのように機能し、どこで耐えうるかを教えること

意図されておらず、サポートもされない用途

  • 本人または機関から禁止されているにもかかわらず、生成物を自作として偽ること
  • 不正に表現しようとするコンテンツの来歴シグナルを無効化すること
  • 自分が所有していない成果物から帰属表示を除去すること
  • プラットフォーム、ライセンス、学術的誠実性に関するポリシーを回避すること

ここに記載されているのは、コードの実行方法に関する技術的制御ではありません。本ソフトウェアが提供される条件と、その作者がサポートする/しないことの表明です。本ソフトウェアは、いかなる種類の保証もなく**「AS IS」(現状のまま)**で提供されます — LICENSE を参照してください。

このツールが出力する数値から何らかの結論を導く前に、範囲と誠実な限界をお読みください。 対象とする方式のいくつかは公開されている検出器では検証できません。README は、それを暗に示すのではなく明言しています。


Contents

  • 研究用のみ
  • 範囲と誠実な限界
  • 理論的基盤
  • インストール
  • クイックスタート
  • Docker
  • localhost を越えたデプロイ
  • CLI
  • ベンチマーク
  • 意味的忠実性
  • 設定
  • トラブルシューティング
  • アーキテクチャ
  • テスト
  • 引用と再利用
  • プロジェクトの状態
  • 参考文献
  • 法的通知と帰属表示

⚠️ 範囲と誠実な限界

このツールが出力する数値から結論を導く前に、これを読んでください。

KGW 検出器について

KGWStatisticalDetector は、Kirchenbauer らによる空白トークン上の green/red リスト方式を数学的に忠実に、かつ自己整合的に実装したものです。これは、いかなるベンダーの本番透かしのデコーダでもありません。そうしたデコーダは秘密鍵とモデル独自の BPE 語彙に依存します。

その目的は、ベンチマークを現実のものにすることです。KGWWatermarkEmbedder が本物の透かしを埋め込み、パイプラインがそれを攻撃し、対応する検出器が実際の低減量を測定します。これはこの方式に対する攻撃の真の測定です。ベンダーの透かしには適用できません。


📖 理論的基盤

テキスト — KGW green/red リスト

語彙 $V$ は、各ステップ $t$ において、直前の文脈をシードとしたハッシュによって分割されます:

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

サイズ $\gamma|V|$ の green リスト $G_t$ と red リスト $R_t$ に分割されます。green ロジットにはバイアス $\delta > 0$ が加算されます:

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

検出は green ヒットを数えます。$H_0$ の下では $\text{Binomial}(T, \gamma)$ に従うため、次式になります:

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

$z > 4.0$($p < 3\times10^{-5}$)の場合、合成と判定されます。

なぜパラフレーズが攻撃になるのか: 透かしは完全に局所的な n-gram 遷移の中に存在します。透かしのないモデルで表層形を書き換えると、すべての位置が再シードされます。これは透かし文献における標準的なロバスト性攻撃です。

なぜ長さが重要なのか: $z$ は $\sqrt{T}$ に比例して増大します。green 割合 0.70 の 100 トークンの文章では $z \approx 3.9$ にしか達しません — 閾値未満です。検出には数百トークンが必要であり、意味のあるベンチマークフィクスチャにも同様に数百トークンが必要です。

画像 — C2PA と周波数領域埋め込み

  • C2PA / JUMBF: JPEG の APP11 セグメント、PNG の tEXt/iTXt チャンク、または WebP/AVIF の c2pa ボックス内にある署名付きマニフェスト。署名はピクセルデータを対象としているため、素のサンプルバッファから再エンコードすれば、JUMBF を一切解析せずに除去できます。
  • SynthID-Image: DCT/DWT 係数のシフト。高周波の詳細サブバンドをソフトしきい値処理することで攻撃します。
  • Tree-Ring: 初期拡散潜在変数における円対称パターンで、フーリエ位相のコヒーレントな構造として残存します。振幅を保ったまま中周波の環状領域の位相をランダム化することで攻撃します — そのため画像は視覚的に同一のままです。

オーディオ — AudioSeal / SynthID-Audio

閾値以下の位相変調と低振幅のスペクトル付加です。音声基本周波数より上の位相ランダム化、非臨界帯域におけるバンドストップ・ノッチのシフト、心理音響的再量子化によって攻撃します。


📦 インストール

要件

Python3.10、3.11、または 3.12
OSLinux、macOS(Intel および Apple Silicon)、WSL2 経由の Windows
任意Ollama または OpenAI 互換サーバー — テキストの透かし除去に必要
任意Compose v2 を備えた Docker 20.10+

ソースから```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:~
### オプションの追加機能```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]"

[nli] がない場合、フィデリティゲートは不変条件のみで動作します — それでも実際のチェックではありますが、 ロールの入れ替えには気づきません。セマンティック・フィデリティ を参照してください。

インストールの確認```bash

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

root@kitploit:~
---

## 🚀 クイックスタート

### 1. ローカル書き換えモデルをセットアップする

テキストの透かし除去には、透かしのないローカルモデルが必要です。それがない場合、NullOriginは不可視文字を削除しますが、
**統計的透かしはそのまま残ります** — そして、その旨を明示します。```bash
ollama serve                    # in a separate terminal
ollama pull llama3.2:3b         # or any instruct model you prefer

別のモデルを使用していますか?NullOrigin をそれに向けてください:```bash export NULLORIGIN_PARAPHRASER_MODEL=qwen3:4b export NULLORIGIN_PARAPHRASER_TIMEOUT=900 # reasoning models are slow

root@kitploit:~
### 2. プロキシを起動する```bash
nullorigin run

Input content is missing — the chunk to translate was not included after "INPUT:". Please provide the source text for chunk 13 of 59.```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. クライアントをその宛先に向ける```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"}]}'

ストリーミング(SSE)とGemini(/v1beta/models/...)は同じ方法で処理されます。 x-nullorigin-providerヘッダーがアップストリームを選択し、転送前に削除されます。 あなたの認証ヘッダーはそのまま通過します。


🐳 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:~
Composeスタックは、プライベートブリッジネットワーク上でNullOriginとOllamaサイドカーを実行します。
プロキシコンテナは `0.0.0.0` にバインドします — コンテナ内では正しい設定です — そしてポート8080のみが
ホストに公開されます。

スタンドアロンイメージ:```bash
docker build -t nullorigin:1.0.0 .
docker run -d -p 8080:8080 \
  -e NULLORIGIN_PARAPHRASER_BACKEND=none \
  nullorigin:1.0.0

便利なコマンド:```bash docker compose logs -f nullorigin docker compose down # stop docker compose down -v # stop and delete the Ollama model volume

root@kitploit:~
---

## 🔒 localhost を超えたデプロイ

**NullOrigin はデフォルトで `127.0.0.1` にバインドされ、テレメトリトークンなしでは公開インターフェースへのバインドを拒否します。** 上流 API の資格情報を中継するため、これは意図的な設計です:```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

適切に公開するには:```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**, and an **auth layer**.

### Threat model

NullOrigin is a **local reverse proxy that relays your upstream API credentials**. That
single fact drives its security posture.

| Control | Default | Why |
| --- | --- | --- |
| Bind address | `127.0.0.1` | Loopback only; a public bind is refused unless a telemetry token is set or `--allow-public-bind` is passed. |
| `/telemetry`, `/telemetry/reset` | Open on loopback | Gated by `X-NullOrigin-Token`, constant-time compared, whenever `proxy.telemetry_token` is set. |
| `/health` | Always open | Container probes need it; exposes version and enabled engines, no secrets. |
| Request body size | 100 MiB | The proxy buffers bodies to forward them; larger input is rejected with `413`. |
| SSE buffer | 1 MiB | An upstream that never terminates a frame is flushed, not buffered indefinitely. |
| Container user | non-root | The proxy needs no elevated privileges. |

Known limitations, by design and not defects:

* **No TLS.** It forwards `Authorization` and `x-api-key` verbatim over plain HTTP. Put
  it behind a reverse proxy that terminates HTTPS on any untrusted network.
* **No authentication on the proxy path.** Anyone who can reach the port can proxy
  through it, using their own credentials — NullOrigin neither stores nor injects keys.
* **No rate limiting.** Apply it at the reverse proxy.
* **Credentials are never persisted.** No API key is written to disk or logs; telemetry
  counts requests and sanitization events only.
* Upstream TLS verification stays on, and redirects are not followed.

To report a security issue, email **[email protected]** with `[NullOrigin Security]` in
the subject.

Telemetry with a token set:```bash
curl -H "X-NullOrigin-Token: $NULLORIGIN_TELEMETRY_TOKEN" http://localhost:8080/telemetry

/health は決してゲートされないため、コンテナプローブは動作し続けます。


🛠️ 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:~
### 対応フォーマット

| 種類 | 拡張子 | 備考 |
| --- | --- | --- |
| **画像** | `.png` `.jpg` `.jpeg` `.jfif` `.webp` `.tif` `.tiff` `.bmp` `.gif` `.ico` `.avif` `.jp2` | すべてのPILモード(RGB、RGBA、L、LA、P、1、I;16、CMYK、YCbCr)に対応。アニメーションGIF/WebPとマルチページTIFFは、すべてのフレームとそのタイミングを保持します。64px未満の画像は正確な寸法を維持します。 |
| **音声** | `.wav` `.wave` | 8/16/32ビット整数、32ビット浮動小数点。モノラルからマルチチャンネルまで、任意のサンプルレートに対応。ゼロ長ファイルもラウンドトリップします。 |
| **文書** | `.docx` `.docm` `.dotx` `.pptx` `.pptm` `.xlsx` `.xlsm` | OOXMLの3つの方言すべてに対応。テキストランは本文、ヘッダー、フッター、脚注、注記、共有文字列にわたってサニタイズされ、`docProps`メタデータは削除され、その他のすべてのパーツはバイト単位でコピーされます。 |
| **PDF** | `.pdf` | `/Info`辞書、XMPパケット、埋め込み添付ファイル、JavaScriptを削除。ページ、テキスト、ジオメトリは保持されます。パスワード保護されたファイルは拒否されます。後述の注意事項を参照してください。 |
| **ソースコード** | `.py` `.js` `.ts` `.go` `.rs` `.java` `.c` `.cpp` `.rb` `.php` `.sh` `.sql` + さらに50以上 | Trojan Source(トロイのソース)とホモグリフのスキャン。**NFKC変換なし、言い換えなし** — 後述参照。 |
| **テキスト** | その他デコード可能なもの | UTF-8、UTF-8 BOM、UTF-16、UTF-32、CP1252、Latin-1 — 自動検出され、**同じエンコーディングで書き戻されます**。 |

その他はすべて、UTF-8として読み取られて破損するのではなく、**具体的なガイダンス付きで拒否**されます — `.mp3`は`ffmpeg -i in.mp3 out.wav`を案内され、レガシーな`.doc`/`.ppt`/`.xls`はOOXMLとして再保存するよう案内されます。拒否されたファイルが出力を生成することは決してありません。

上記のすべてのフォーマットにわたる69ファイルのコーパスで検証済み: **59件が正常に処理され、10件がクリーンに拒否され、クラッシュゼロ、破損出力ゼロ。**

### コードはリライターから除外される

アシスタントの応答は散文とコードが1つの文字列に混在しています。全体をパラフレーズモデルに渡すと、散文と一緒にコードも書き換えられます — そしてどちらにせよzスコアは低下するため、後段の処理は何も気づきません。

したがって、応答は何かを書き換える前にセグメント分割されます:

| セグメント | 処理 |
| --- | --- |
| 散文 | Unicodeクリーニング後、書き換え |
| フェンスで囲まれたブロック(``` と ~~~) | 不可視文字と双方向(bidi)文字を除去。**NFKC変換なし、決して書き換えなし。** |
| インラインの `` `code` `` スパン | 同様 |

これはストリーミング経路でも同様で、フェンスがあるデルタで開き、数デルタ後に閉じます。境界にまたがるデルタは行単位で分割されるため、閉じる ``` とその後の散文は異なる扱いを受けます。閉じられていないフェンスはフェイルセーフに動作します: 残りの部分は書き換えられるのではなく保護されます。

以前の動作が必要な場合は、`text.protect_code_blocks: false`で無効にできます。

### ソースコードファイル: 透かし除去ではなくセキュリティスキャン

**AI生成のソースコードには透かしはありません。** コード出力に透かしを入れるプロバイダーは存在せず、公開された検出器も存在しません。透かしを除去できると主張する者は、何かを売りつけているだけです。

ソースコードに*実際に*存在するのは、現実的で公表された攻撃対象領域です:

* **Trojan Source**([CVE-2021-42574](https://nvd.nist.gov/vuln/detail/CVE-2021-42574)、Boucher & Anderson 2021)— 双方向制御文字は、コードの*コンパイル*方法を変えることなく*表示*方法を並べ替えます。レビュアーがあるプログラムを承認しても、コンパイラは別のプログラムをビルドします。
* **ホモグリフ識別子**([CVE-2021-42694](https://nvd.nist.gov/vuln/detail/CVE-2021-42694))— ラテン文字の`a`の代わりにキリル文字の`а`を使うと、見た目が同一の2つの名前が生成されます。```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⁩⁦":

パージ後、その行は if access_level != "user // Check if admin": と読めます — 「コメント」はずっと文字列の中にあったのです。

コードパスが意図的に行わない3つのこと — 一般的なテキストパスはこれら3つをすべて行っており、それぞれがソース上のバグです。

  1. NFKC正規化を行わない。 文字列リテラルの値を書き換えます: "Hello" は "Hello" に、"office" は "office" になりました。これはプログラムが比較・ハッシュ・ 送信する内容を変えます。
  2. 言い換えを行わない。 コードを書き換えモデルに送ると、実行できないコードが生成されます。
  3. ホモグリフは報告され、折り畳まれません。 キリル文字の а を折り畳むと、コンパイラが現在別物として扱う2つの識別子 が統合され、動作を静かに変えます。深刻度は、実際の攻撃シグネチャである混在スクリプトトークン (totаl) に対してのみ MEDIUM です。 別の文字体系で完全に書かれた単語 は通常の外国語テキストであり、INFO と評価されます。レビュー後に --fold-homoglyphs-in-code でオプトインしてください。

inspect --json は、検出結果ごとに深刻度・行・列・コードポイントを出力するため、pre-commit や PR ゲート として CI に組み込めます。

PDF: 削除されるものと削除されないもの

削除されるもの(検証済み): /Info ディクショナリ(Author, Title, Subject, Keywords, Creator, Producer, CreationDate, ModDate)、/Root/Metadata 内の XMP パケット、埋め込み ファイル添付、およびドキュメントレベルの JavaScript。ページ、テキスト、ページジオメトリは 正確に保持されます。この操作は冪等でバイト単位で安定しています。

検出されるが削除されないもの: ページコンテンツストリーム内の不可視文字。PDF はフォント固有のエンコーディングでテキストをグリフごとに描画します — CIDキー付きフォントのゼロ幅スペースは リテラルな U+200B ではなく2バイトのグリフインデックスです — そのため、汎用的な書き換えは クリーンにするどころかレイアウトを壊します。inspect は件数を報告し、purge は沈黙せずに警告を出力します。沈黙は「何もなかった」と読まれるためです。 削除するには、テキストを抽出し、nullorigin purge を実行し、PDF を 再生成してください。

--strip-annotations は利用可能ですが、デフォルトではオフです。アノテーションにはリンクと フォームフィールドが含まれ、コメントだけではありません。そのため、削除するとドキュメントの動作が変わります。

タイポグラフィは透かしではない

emダッシュ、カール引用符、省略記号は一般的なワードプロセッサの出力です。NullOrigin は デフォルトでこれらを保持し、本当の検出結果とは別に報告します。なぜなら、 それらを平坦化すると、何もサニタイズせずにドキュメントを劣化させるだけだからです。 特に ASCII 出力が必要な場合は --flatten-typography を使用してください。

クロススクリプトの紛らわしい文字は別です — 英語テキストの単語中にあるキリル文字 о には 正当な用途がありません — そのため、これらはデフォルトで折り畳まれます。

--verify は成功を断言するのではなく、前後の測定値を報告します:```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:~
バックエンドに到達できない場合、それはstderrに警告として報告されます — 警告なしの
フォールバックは、成功したサニタイゼーションとまったく同じに見えるでしょう。

---

## 📊 ベンチマーキング```bash
nullorigin build-datasets
nullorigin benchmark

すべての値はその場で測定されます: テキストはKGWWatermarkEmbedderで透かしが入れられ、 実際のパイプラインに通され、対応する検出器で再スコアリングされます。ランナーは しきい値が満たされない場合は非ゼロで終了し、その理由を説明します。

しきい値(プロジェクト指示より):

指標目標
サニタイズ後zスコア$\lvert z\rvert \le 1.5$
意味的類似度$\ge 0.92$
画像SSIM$\ge 0.95$
画像PSNR$\ge 36$ dB

測定結果

datasets/text/watermarked_kgw.json 上の全文セクションを、Ollama (qwen3:4b)経由でMシリーズのMacBook上で書き換え(1パッセージあたり約150秒):```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:~
すべての透かし入りサンプルは、検出された状態から未検出の状態へ移行しました。`kgw_003` は z = 1.271 にあり、閾値を下回っていますが、それに最も近い値です。これがこの攻撃の正直な姿です。すなわち、統計的なものであり、保証ではありません。

メディア(画像フィクスチャ全体で測定):```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

両方の画像しきい値を通過します(SSIM ≥ 0.95、PSNR ≥ 36 dB)。数値はモデル、ハードウェア、および文章によって異なります。

意味的忠実性: zスコアの低下は意味が保持されていることの証拠にはならない

事実を変えるリライトは、ウォーターマーク指標では忠実なリライトとまったく同じスコアになります。これに対する明白なチェックは機能せず、あまり明白でないチェックも同様に機能しません。6つのドリフトケースと忠実な対照を測定しました:

語彙の重複は逆転している。 意味を破壊するすべての編集は、忠実なリライトよりも高いスコアを獲得しました。なぜなら、優れたパラフレーズはソースと共有するn-gramが少ないのに対し、破壊されたものはほぼすべてを共有するからです。

埋め込みコサインはこれを解決しない。 6つの破損ケースのうち3つが0.92のしきい値を通過します。"Alice paid Bob" と "Bob paid Alice" は同じ単語の袋(bag of words)であり、0.985を獲得します。"must not disable" → "must disable" は0.947を獲得します。文埋め込みは話題の関連性をエンコードするのであって、真実性をエンコードするのではありません。

したがって、忠実性は2つの層でチェックされ、そのどちらもコサインではありません:

  1. 不変条件 — 数値、否定の数、法助動詞の強度、数量詞の強度、URL、メールアドレス、識別子、固有表現。決定論的で、依存関係がなく、説明可能です(negation count changed: 1 → 0)。法助動詞と数量詞は意味クラスで比較されるため、may → might は合格し、may → must は不合格になります。すべてのエンティティが残る役割の入れ替えには気づきません。
  2. 双方向含意 — 各テキストが互いを含意する場合に限り、意味が保持されます。カウントでは捉えられない役割の入れ替えなどを捉え、その非対称性は診断的です(ヘッジの削除は a⇒b 0.991、b⇒a 0.011 とスコア付けされました)。nullorigin[nli] が必要です。これがない場合、制限は隠されずに報告されます。

これはレポートではなくゲートである

損傷したテキストがすでに返されてしまった場合、事後的にドリフトを測定しても役に立ちません。チェックが失敗すると、より低い温度で再試行されます — ドリフトは温度に起因するためです — そして再試行の予算を使い切ると、元のテキストを ok=False と理由とともに返します。```yaml text: fidelity: enabled: true max_retries: 2 temperature_step: 0.25 use_nli: true nli_threshold: 0.5

root@kitploit:~
これはまた、攻撃とリスクが一つのダイヤルを共有することを意味する:温度を上げると
zスコアが下がり、*かつ* ドリフト率が上がる。ベンチマークはこれらを独立したチェックとしてではなく、
一緒に報告する。

### その他のメトリクス

* **Perplexity** — `torch` + `transformers` を使用した実際の GPT-2 PPL、それ以外の場合は
  `unigram_entropy_proxy` を使用し、近似としてフラグ付けされ、公開されたPPLとは**比較できません**。
* **コサイン類似度** は参照専用として引き続き `mean_cosine_or_lexical` として報告されます。
  上記の表の理由により、これはもはや合格/不合格のゲートではありません。

## ⚙️ 構成

解決順序(低いものから高いものへ):

1. 組み込みのデフォルト
2. `nullorigin.yaml`(`./`、`../`、`/app/`、または `$NULLORIGIN_CONFIG` で検索)
3. `NULLORIGIN_*` 環境変数
4. 明示的なCLIフラグ

### 主要な設定

| 設定 | デフォルト | 備考 |
| --- | --- | --- |
| `proxy.host` | `127.0.0.1` | ループバック。テレメトリトークンなしでは公開バインドは拒否されます。 |
| `proxy.port` | `8080` | |
| `proxy.default_provider` | `openai` | `x-nullorigin-provider` ヘッダーが送信されない場合に使用されます。 |
| `proxy.telemetry_token` | `""` | `/telemetry` と `/telemetry/reset` を保護します。 |
| `proxy.max_request_bytes` | `104857600` | 100 MiB; それを超えるボディは `413` を受け取ります。 |
| `text.paraphraser.backend` | `ollama` | `none` \| `ollama` \| `openai_compatible` \| `llama_cpp` \| `lexical`。`none` は統計的透かしをそのまま残します。`lexical` はモデルを必要としませんが、はるかに弱い攻撃です。 |
| `text.clean_unicode` | `true` | ゼロ幅およびTagsブロックの除去。 |
| `text.fold_homoglyphs` | `true` | キリル文字/ギリシャ文字の紛らわしい文字をASCIIに変換。 |
| `text.stream_window_tokens` | `40` | ストリーミングスパンが書き換えられる前にバッファリングされる差分。 |
| `media.crop_mode` | `trim` | `trim` はリサンプリングなしで座標をシフトします。`resample` は正確な寸法を復元しますが、0.5%のクロップでもおよそSSIM 0.81 / PSNR 31 dBのコストがかかります。`none` は幾何学的パスを無効にします。 |
| `audio.low_cut_hz` | `800.0` | この周波数以下の位相は了解度のために保持されます。 |

### 環境変数```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

🩺 トラブルシューティング

model 'llama3.2:3b' not found 設定されたモデルがプルされていません。ollama list を実行して何があるか確認し、ollama pull llama3.2:3b を実行するか、NULLORIGIN_PARAPHRASER_MODEL を既に保持しているモデルに設定してください。

WARNING: ollama backend unavailable (ReadTimeout) リライトが text.paraphraser.timeout_seconds(デフォルト 120 秒)を超えました。qwen3 などの推論モデルは、CPU 上では段落あたり 150 秒以上かかることがよくあります。次のようにして値を引き上げてください: export NULLORIGIN_PARAPHRASER_TIMEOUT=900。または、より小さな instruct モデルを使用してください。

nullorigin benchmark が pass_no_detection: FAIL で exit 1 になる 意図した動作です。リライトバックエンドに到達できなかったため、unicode レイヤーのみが実行され、統計的ウォーターマークが残りました。Ollama を起動するか、依存関係なしで比較するためにバックエンドを lexical に設定してください。

semantic_check: INCONCLUSIVE [metrics] エクストラがない場合は想定どおりです。Metric honesty を参照してください。

Error: Refusing to bind 0.0.0.0 without a telemetry token 意図的です。Deploying beyond localhost を参照してください。

Multiple top-level packages discovered in a flat-layout 古いチェックアウトを使用しています。pyproject.toml には明示的なパッケージリストが設定されています。最新版をプルしてください。

非同期テストで、async プラグインがないという UsageError が報告される 意図的です。これがないと、pytest は async def テストを await せずに合格として報告します。pip install -e ".[dev]" を実行してください。

Docker: compose up 直後に curl: (7) Failed to connect ヘルスチェックには 10 秒の開始期間があります。待ってから、docker compose logs nullorigin を確認してください。


🏗️ アーキテクチャ```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:~
### レイアウト```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

🧪 テスト```bash

pytest -q

root@kitploit:~
384 テスト。このスイートは、敵対的なチャンク境界に対する SSE フレームパーサー、プロキシストリーミングのライフサイクル、すべての PIL 画像モード、閉形式の値とブルートフォース参照実装の両方に対する SSIM、およびデータセットの透かし検出可能性をカバーしています。

非同期テストは、非同期プラグインがインストールされていない場合、黙ってスキップするのではなく、明示的に失敗します。

---

## 📖 引用と再利用

Apache-2.0 ライセンスのもとで提供されており、著作権表示と **Muhammad Rakibul Islam** への帰属が保持される限り、使用、変更、再配布が許可されています。[LICENSE](https://github.com/rakib-nyc/nullorigin/blob/HEAD/LICENSE) と [NOTICE](https://github.com/rakib-nyc/nullorigin/blob/HEAD/NOTICE) を参照してください。

この成果が出版物で使用される場合は、次のように引用してください:```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}
}

このリポジトリは完成した研究成果物として公開されており、プルリクエストは受け付けていません。 ライセンスの条件に基づき、自由にフォークできます。質問や発見は [email protected] まで電子メールで歓迎します。


🗺️ プロジェクト状況

バージョン1.0.0。このスイートは仕様に対して完全であり、十分にテスト済みですが、 以下の既知の制約があります:

  • SynthID、Tree-Ring、およびAudioSealに対する有効性は、ここでは検証できません — それを 測定する公開検出器は存在しないためです。摂動は実装されていますが、その主張は 行われていません。
  • 意味的ドリフトは、不変条件とオプションのNLIによって制御されています。[nli]がないと、すべての エンティティを保持するロールの入れ替えは検出できず、レポートにもその旨が記載されています。
  • ローカル推論モデルでのレイテンシ(パッセージあたり約150秒)により、テキストパスは インタラクティブな使用には適していません。より小さいインストラクトモデルであれば、はるかに高速です。
  • TLSなし、リクエスト認証なし — これは設計によるものです。リバースプロキシの背後で実行してください。

CHANGELOG.md でリリース履歴を参照してください。


📚 参考文献

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

📜 法的通知と帰属

  • 著者&作成者: Muhammad Rakibul Islam
  • 連絡先: [email protected]
  • ライセンス: Apache License, Version 2.0

このリポジトリは、統計調査、プライバシー評価、ウォーターマーキングの堅牢性ベンチマーク、および 暗号耐性テストのために公開された研究グレードの成果物です。```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:~
**保証はありません。** 本ソフトウェアは「現状のまま」で提供され、明示または黙示を問わず、
いかなる種類の保証もありません。
ツールをダウンロード
レイヤー実際の動作
不可視文字完全に有効。 ゼロ幅文字、双方向制御文字、変異選択子、Unicode Tags ブロックのペイロードは完全に除去され、その数が報告されます。異なるスクリプト間のホモグリフ紛らわし文字(キリル文字/ギリシャ文字が ASCII として描画されるもの)は畳み込まれます。
文書メタデータ (.docx)完全に有効。 docProps から作成者、最終編集者、リビジョン数、タイムスタンプ、テンプレート、アプリケーションのバージョンが消去され、書式はバイト単位で保持されます。
C2PA / EXIF / XMP完全に有効。 画像は生のピクセルサンプルから新しいコンテナとして再構築されるため、署名付き JUMBF マニフェストとすべてのメタデータが消去されます。タグ付きフィクスチャに対するテストで検証済み。
KGW 統計透かし書き換えバックエンドに完全に依存します。 ローカルモデルが設定されていない場合、統計透かしは生き残ります — このツールは、それを暗に示すのではなく明言します。
SynthID-Text / SynthID-Image / Tree-Ringここでは検証できません。 これらは秘密鍵とプロプライエタリなデコーダを使用します。NullOrigin は文献に記載された摂動を適用しますが、実際の検出器を無効化するという主張は一切しません。比較測定できる公開検出器が存在しないためです。
AudioSeal / SynthID-Audioここでは検証できません。理由は同じです。
ケースlexical_f1埋め込みコサイン双方向NLI
否定の欠落0.700.77 ✓0.000 ✓
数値 5 → 500.820.81 ✓0.000 ✓
エンティティ/役割の入れ替え0.810.985 ✗0.000 ✓
数量詞 all → some0.880.91 ✓0.000 ✓
ヘッジの削除0.270.953 ✗0.011 ✓
"must not" → "must"0.830.947 ✗0.000 ✓
忠実なリライト0.330.931 ✓0.998 ✓