
يتجاوز العلامات المائية لنصوص LLM عن طريق حقن محددات الاختلاف في يونيكود؛ يشمل مولّد SynthID، وكاشف mean-g، ودفاعات التطبيع، وتجارب الإنتروبيا.
مرحبًا، ألوش هنا ✌🏻
نعم، لكن عائلة هجوم واحدة فقط تنجح، وهي ليست التي يظنها الجميع.
محددات الاختلاف في Unicode (الفئة Mn، من U+FE00 إلى U+FE0F ومن U+E0100 إلى U+E01EF) تُنزل الكاشف إلى ما دون العتبة وتبقى هناك. كل هجوم بالحروف غير المرئية الآخر الذي جرّبته يُلغى بالكامل بسطر واحد من تطبيع الإدخال. محددات الاختلاف لا تُلغى، لأنها نقاط رمزية ذات معنى (عرض الإيموجي، متغيرات CJK) لا يستطيع NFKC طيّها ولا ينبغي له ذلك.
أُعيدت التجربة على ثلاثة نماذج وفي مجالين:
| النموذج | المجال | خط الأساس z | بعد vs16_30 | معدل التحرير |
|---|---|---|---|---|
| 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. الثلاثة جميعًا تقع دونها، وتبقى دونها بعد التطبيع (0.09 و0.45 و-0.78 على التوالي). يُعرض النص بشكل مطابق للقارئ البشري.
الاكتشاف الحقيقي الثاني لا يحتاج إلى أي هجوم: النص منخفض الإنتروبيا بالكاد يكون موسومًا بالماء من الأساس. توليد الكود بواسطة Qwen3.8-27B يعطي خط أساس نظيفًا عند z = 4.31، وهو قريب بالفعل من العتبة دون فعل أي شيء.
شركة أنثروبيك (وقبلها Google DeepMind في ورقة SynthID-Text) وسمت النص المولَّد بانحياز عينات التوكن عبر بطولة بمفتاح. الإشارة تكمن في أي التوكنات اختيرت، لا في أي حرف خفي. أردت معرفة مدى هشاشة ذلك أمام شخص محفّز يستخدم البحث والاستبدال، لذا بنيت المولّد وكاشف mean-g غير مدرب ورميت الهجمات عليه.
عتبة الكاشف هي z = 2.33 (معدل إيجابيات كاذبة 1%). فوق ذلك = تم اكتشاف العلامة المائية. ولّدت نصًا موسومًا، هاجمته، أعدت تجزئته إلى توكنات، ثم قيّمته. يحمل كل جدول نتائج عنصر تحكم roundtrip (نص موسوم لم يتعرض لهجوم) حتى ترى أن الكاشف يعمل فعلًا في ذلك الصف. خلال هذه الدراسة، تسبب خلل مرتين في انهيار كل قيم z إلى الصفر، ولم يكشف الخلل سوى عنصر التحكم.
ينقسم سطح الهجوم بوضوح حسب فئة Unicode، والتي اتضح أنها القصة كلها.
ما ينجح (الفئة Mn، علامات غير متباعدة):
ما لا ينجح (الفئة Cf، أحرف تنسيق):
أحرف الفئة Cf هي تنسيق خالص دون أي محتوى دلالي، لذا يمكن للمطبِّع إزالتها بالجملة دون خسارة شيء. محددات الاختلاف من الفئة Mn تحمل معنى حقيقيًا في نصوص الإيموجي ونصوص CJK، لذا فإن إزالتها بشكل عشوائي سيفسد المستندات الشرعية. هذا التباين هو سبب كون إحدى العائلتين قابلة للدفاع عنها والأخرى ليست كذلك.
النطاق العملي: يتطلب هذا لمس حوالي 20% أو أكثر من الأحرف لدفع خط أساس قوي إلى ما دون العتبة، لكن الأحرف المُدرجة غير مرئية، لذا يظل النص مقروءًا بشكل طبيعي في أي معدل تحرير. تم التحقق من أنه مطابق بصريًا، انظر src/fidelity_check.py. أربع عائلات تُدرج أحرفًا لا تُظهر شيئًا؛ المتجانسات الشكلية (homoglyphs) هي الاستثناء الصريح (تعتمد على الخط، وليست مضمونة الخفاء).
خوفي الأولي كان الأمر الممل: أن الشرطات الطويلة وتحويل "و" إلى "&" وإزالة ترميز Markdown ستعمل ببساطة، فتتحول العلامة المائية إلى مجرد مسرح أمني. كثير من الناس على الإنترنت يفترضون ذلك تمامًا.
لا ينجح ذلك. سلم التحرير السطحي بأكمله على gpt-oss-20b حتى 32k توكنًا:
عبر ثلاثة نماذج (0.8B و4B و20B = 294 خلية)، عبرت خلية واحدة فقط العتبة: حذف 39% من كل كلمة عند أقصر طول على نموذج 4B. هذا ليس هجومًا، هذا تمزيق للمستند.
أمران فاجآني:
الآلية الكاملة وجداول كل هجوم في docs/FINDINGS.md.
جرّب النسخة التفاعلية ← عينات حقيقية من الدراسة مع مفتاح إظهار قبل/بعد، إضافة إلى ساحة تجارب لتشغيل تحويل الهجوم على نصك الخاص. لن يخبرك ما إذا كان النص الملصق عشوائيًا موسومًا بالماء فعلًا (فهذا يتطلب مفتاحًا لا نملكه)، وهو يوضح ذلك؛ انظر site/ للاطلاع على سكربت التوليد.
تعتمد العلامة المائية على درجة عدم اليقين لكل توكن في النموذج. عندما يكون النموذج واثقًا من التوكن التالي، لا تجد البطولة مجالًا لتحييزه، فلا تدخل أي إشارة. وهذا يعني أن العلامة ضعيفة على النص منخفض الإنتروبيا، والكود منخفض الإنتروبيا.
نموذج Qwen3.5-4B، نثر مقابل كود، عينات من 512 توكنًا، دون أي هجوم:
| المجال | الإنتروبيا | z |
|---|---|---|
| نثر | 1.19 bits/tok | 11.1 |
| كود | 0.55 bits/tok | 5.0 |
نسبة z 0.45x، ونسبة الإنتروبيا 0.46x، وهما تتحركان معًا، وهذا هو أثر الآلية الظاهر. 3 من 8 عينات كود هبطت إلى عتبة الكشف أو دونها من تلقاء نفسها. أكثرها إحكامًا (خوارزمية مجردة، 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 يستخدم معالج GPU الخاص بـ HF (أسرع بكثير على نماذج المفردات الكبيرة؛ على H100 كان هذا هو الفرق بين 0% و46% من استخدام GPU).
يتطلب الوسم المائي توزيع التوكن التالي الكامل، لذا يعمل عبر transformers (CUDA MXFP4 الأصلي، أو MPS/CPU). لا يمكن لـ Ollama وllama.cpp فعل ذلك، لأنهما لا يعرضان logits أثناء التوليد. على Apple Silicon، يجسر src/synthid_mlx.py توليد MLX إلى رياضيات الوسم المائي؛ وهو مُتحقق منه كمتطابق بتًّا ببت مع مرجع HF.

(الميم الذي بدأ كل هذا. تبيّن أنك تحتاج إلى محددات اختلاف، لا إلى بحث واستبدال.)
ملاحظة: استخدمت Claude Code بكثافة في التنفيذ وإعادة تشغيل التجارب عبر أربعة أجهزة (جهاز Mac، وبطاقة 4090 الخاصة بي، و3090 مستأجرة، ووحدة H100). تصميم التجارب، والهجمات التي أردت تجربتها، وقرارات التأطير هي مني. أصرّ كلود على قياس كل هجوم مقابل دفاعه الخاص، ولهذا تحتوي جداول الإخفاء (stego) على عمود خام وعمود مُطبَّع بدل العمود الخام فقط؛ هذا ما حوّل عبارة "الأحرف غير المرئية تكسرها" إلى النتيجة الفعلية، وهي أن أحرف الفئة Mn فقط هي التي تنجو من المطبِّع.
| الهجوم | ما يفعله | معدل التحرير | ينجو من التطبيع؟ |
|---|
vs16_30 | محدد اختلاف بعد ~30% من الأحرف | 57% | نعم |
vs16 | محدد اختلاف بعد ~10% من الأحرف | 23% | نعم (z 3.46) |
vs_supp | محددات المستوى الإضافي (U+E0100+) | 24% | نعم (z 3.40) |
homoglyph | а سيريلية بدل a لاتينية (الفئة Ll) | 9% | نعم، لكن التأثير ضعيف |
| الهجوم | z الخام | z بعد التطبيع | الحكم |
|---|
zwsp_30 | -0.09 | 35.68 | أُلغي بالكامل |
combo | 0.92 | 35.68 | أُلغي بالكامل |
bidi | 24.37 | 35.68 | أُلغي بالكامل |
nbsp | 41.04 | 46.51 | بالكاد يغيّره |
| الهجوم | معدل التحرير | z @ 1k | z @ 32k |
|---|
| roundtrip (مجموعة ضابطة) | 0% | 25.7 | 104.3 |
| شرطة طويلة إلى واصلة | ~0% | 26.4 | 113.7 |
| إزالة كل ترميز Markdown | 13.6% | 27.2 | 103.3 |
| من الإنجليزية الأمريكية إلى البريطانية + اختصارات | 1.3% | ~28 | ~100 |
| حذف 40% من كل كلمة | 38% | 4.9 | 25.4 |