Hola、Aloshです ✌🏻
はい。ただし、有効な攻撃は1つのファミリーだけであり、それは誰もが想定しているものではありません。
Unicode 変体選択子(カテゴリMn、U+FE00〜U+FE0FおよびU+E0100〜U+E01EF)は、検出器をしきい値未満に追い込み、その状態を維持します。私が試した他のすべての不可視文字攻撃は、1行の入力正規化によって完全に元に戻されます。変体選択子はそうなりません。なぜなら、これらはNFKCが折りたたむことができず、また折りたたむべきではない、意味のあるコードポイント(絵文字表現、CJK異体字)だからです。
3つのモデル、2つのドメインで再現:
| model | domain | baseline z | after vs16_30 | edit rate |
|---|---|---|---|---|
| gpt-oss-20b | 散文 | 45.03 | 0.72 | 57% |
| gpt-oss-20b | コード | 37.24 | 0.68 | 58% |
| Qwen3.8-27B | 散文 | 35.50 | -0.67 | 57% |
しきい値はz = 2.33です。3つすべてがその下に到達し、正規化後も下のままです(それぞれ0.09、0.45、-0.78)。テキストは人間の読者にはまったく同じように表示されます。
2つ目の実際の発見には攻撃がまったく必要ありません:低エントロピーテキストはそもそもほとんど透かしが入っていません。 Qwen3.8-27Bのコード生成は何もしなくてもz = 4.31というクリーンなベースラインを持ち、すでにしきい値に近い値です。
Anthropic(およびその前のGoogle DeepMind、SynthID-Text論文)は、鍵付きトーナメントでトークンサンプリングにバイアスをかけることにより、生成テキストに透かしを入れました。信号はどのトークンが選ばれたかに存在し、隠し文字には存在しません。私は、検索と置換を使う意欲のある人に対してこれがどの程度脆弱かを知りたかったので、ジェネレーターと未学習の平均g検出器を構築し、攻撃を仕掛けました。
検出しきい値はz = 2.33(1%の偽陽性率)です。それを超えると透かしが検出されたことになります。私は透かし入りテキストを生成し、攻撃し、再トークン化してスコアリングしました。すべての結果テーブルにはroundtripコントロール(攻撃されていない透かし入りテキスト)が含まれており、その行で検出器が実際に機能していることを確認できます。この研究で2回、バグによりすべてのzがゼロに潰れたことがありましたが、コントロールだけがそれに気付くことができました。
攻撃面はUnicodeカテゴリによってきれいに分割され、それがすべての本質であることが判明しました。
機能するもの(カテゴリMn、非間隔結合記号):
機能しないもの(カテゴリCf、書式文字):
Cf文字は意味内容のない純粋な書式設定であるため、正規化子はそれらをまとめて削除しても失うものはありません。Mn変体選択子は絵文字やCJKテキストで実際の意味を持つため、それらを一律に削除すると正当な文書が破損します。この非対称性が、一方のファミリーが防御可能であり、もう一方がそうでない理由です。
実際の適用範囲: 強いベースラインをしきい値未満に押し下げるには、おおよそ20%以上の文字に触れる必要がありますが、挿入される文字は不可視であるため、どの編集率でもテキストは普通に読めます。視覚的に同一であることが検証されており、src/fidelity_check.pyを参照してください。4つのファミリーは何も描画しない文字のみを挿入します。ホモグリフは正直な例外です(フォント依存であり、不可視が保証されているわけではありません)。
私が最初に懸念していたのは退屈な類のものでした。emダッシュや「and」の「&」への置換、Markdownの除去がそのまま機能し、透かしがセキュリティ上の見せかけになるのではないか、ということです。オンラインの多くの人々がまさにそれを想定しています。
それは機能しません。gpt-oss-20bでのサーフェス編集ラダー全体を32kトークンまで試しました:
3つのモデル(0.8B、4B、20B = 294セル)全体で、しきい値を超えたセルは正確に1つだけでした。4Bで最短長においてすべての単語の39%を削除した場合です。それは攻撃ではありません。文書を細断しているだけです。
2つのことに驚きました:
完全なメカニズムと攻撃別のテーブルはdocs/FINDINGS.mdにあります。
インタラクティブ版を試す → 実際の研究サンプルを前後表示トグルで確認でき、さらに自分のテキストに攻撃変換を実行できるプレイグラウンドもあります。任意の貼り付けテキストが本当に透かし入りかどうかは教えてくれません(それには私たちが持っていない鍵が必要です)、そしてその旨が明記されています。ジェネレータースクリプトはsite/を参照してください。
透かしはモデルのトークンごとの不確実性に乗っています。モデルが次のトークンについて確信している場合、トーナメントにはバイアスをかける余地がなく、信号は入りません。つまり、マークは低エントロピーテキストでは弱く、コードは低エントロピーです。
Qwen3.5-4B、散文とコード、512トークンのサンプル、攻撃なし:
| ドメイン | エントロピー | z |
|---|---|---|
| 散文 | 1.19 bits/tok | 11.1 |
| コード | 0.55 bits/tok | 5.0 |
z比は0.45倍、エントロピー比は0.46倍で、両者は一緒に動いており、これがメカニズムの現れです。**8件のコードサンプルのうち3件は、何もしなくても検出しきい値以下に落ちました。**最も厳しいもの(素のアルゴリズム、0.2 bits/token)は1.7で、検出を外しました。
スケールが大きくなるとさらに極端になります。攻撃を一切行わないベースラインz:
| モデル | 散文 | コード | 比率 |
|---|---|---|---|
| gpt-oss-20b | 45.03 | 37.24 | 0.83 |
| Qwen3.8-27B | 35.50 | 4.31 | 0.12 |
Qwen3.8-27Bのコード出力は非常にテンプレート化されているため、クリーンで攻撃されていない透かしはz = 4.31に位置し、2.33のしきい値をわずかに上回るだけです。敵対者は不要です。
これは、ドメイン全体にわたる単一の信頼度しきい値は安全ではなく、短いコードスニペットは透かしをほぼ付与できないことを示しています。JSON、設定、構造化抽出、ボイラープレートにも一般化されます。
これらの検出器のいずれかを出荷する場合、入力の正規化で大部分は解決しますが、すべてではありません:
手順3と4は、素朴な正規化子が見逃すものです。
ギャップについて正直に述べます。
src/synthid_robustness.py generator + attack ladder + mean-g detector + normalizer
src/code_vs_prose.py the entropy experiment (with per-token entropy tap)
src/fidelity_check.py proves the stego attacks are visually identical
src/synthid_mlx.py watermarking bridge for Apple Silicon (MLX), validated vs HF
src/prompts_code.py prose / code / mixed prompt sets
src/build_report_data.py assembles results/ into the tables in FINDINGS.md
results/ the JSON this is all computed from
docs/FINDINGS.md every table, the defense hierarchy, the bugs I caught
python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
# generate watermarked docs + run the full attack ladder on a model
MODEL=Qwen/Qwen3.5-4B LENGTHS=1024,2048,4096,8192 N_DOCS=2 \
DOCS=docs_4b.json OUT=res_4b.json python src/synthid_robustness.py
# the entropy experiment (code vs prose)
python src/code_vs_prose.py --model Qwen/Qwen3.5-4B --out res_cvp_4b.json
# the variation-selector / stego attacks, scored raw AND post-normalization
ATTACK_SET=desync DEFENSE=1 PROMPT_SET=prose MODEL=Qwen/Qwen3.5-4B \
DOCS=docs_4b.json OUT=res_defense.json python src/synthid_robustness.py
PROMPT_SETはprose、code、またはmixedを取ります。FAST_WM=1はnumpy透かしブリッジを使用します(強力なCPUを備えた小規模ボキャブラリのモデルで高速)。FAST_WM=0はHFのGPUプロセッサーを使用します(大規模ボキャブラリのモデルでははるかに高速。H100では、これがGPU使用率0%と46%の差でした)。
透かし処理には完全な次トークン分布が必要なため、transformers(CUDAネイティブMXFP4、またはMPS/CPU)を通じて実行されます。Ollamaとllama.cppはそれができません。生成途中のロジットを公開しないからです。Apple Siliconでは、src/synthid_mlx.pyがMLX生成を透かし計算にブリッジします。HF参照とビット単位で同一であることが検証されています。

(すべての始まりとなったミーム。結局必要なのは、検索と置換ではなく変体選択子だった。)
注記: 実装と、4台のマシン(Mac、自分の4090、レンタルした3090、H100)にわたる実験の再実行には、Claude Codeを多用しました。実験設計、試したかった攻撃、フレーミングに関する判断は私のものです。Claudeはすべての攻撃をそれ自身の防御に対して測定することを主張しました。そのため、ステゴのテーブルには生の列だけでなく、生と正規化済みの列があるのです。それが「不可視文字はこれを壊す」を実際の発見、つまり正規化子を生き残るのはMnカテゴリのものだけである、という発見に変えました。
| attack | what it does | edit rate | survives normalization? |
|---|
vs16_30 | 約30%の文字の後に変体選択子 | 57% | はい |
vs16 | 約10%の文字の後に変体選択子 | 23% | はい (z 3.46) |
vs_supp | 追加面の選択子 (U+E0100+) | 24% | はい (z 3.40) |
homoglyph | ラテン文字aの代わりにキリル文字а (カテゴリLl) | 9% | はい、ただし効果は弱い |
| attack | raw z | normalized z | verdict |
|---|
zwsp_30 | -0.09 | 35.68 | 完全に元に戻る |
combo | 0.92 | 35.68 | 完全に元に戻る |
bidi | 24.37 | 35.68 | 完全に元に戻る |
nbsp | 41.04 | 46.51 | ほとんど動かない |
| attack | edit rate | z @ 1k | z @ 32k |
|---|
| roundtrip (コントロール) | 0% | 25.7 | 104.3 |
| emダッシュをハイフンに | ~0% | 26.4 | 113.7 |
| すべての Markdownを除去 | 13.6% | 27.2 | 103.3 |
| 米英語→英英語 + 略語 | 1.3% | ~28 | ~100 |
| すべての単語の40%を削除 | 38% | 4.9 | 25.4 |