Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
claude-awm — Elude i watermark testuali degli LLM iniettando selettori di variazione Unicode; include il generatore SynthID, il rilevatore mean-g, le difese di normalizzazione ed esperimenti sull'entropia. | Kitploit
Strumenti/GitHubGitHub/aloshdenny/claude-awm
SteganografiaPrivacyMachine LearningSicurezza dell'IAAttacco Avversario
GitHubaloshdenny/claude-awm

claude-awm

Elude i watermark testuali degli LLM iniettando selettori di variazione Unicode; include il generatore SynthID, il rilevatore mean-g, le difese di normalizzazione ed esperimenti sull'entropia.

Vedi Repository
1734 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

claude-awm: si può rimuovere una filigrana testuale SynthID modificando il testo?

Hola, sono Alosh ✌🏻

Sì, ma funziona solo una famiglia di attacchi, e non è quella che tutti presumono.

I variation selector Unicode (categoria Mn, da U+FE00 a U+FE0F e da U+E0100 a U+E01EF) portano il rilevatore sotto la soglia e restano lì. Ogni altro attacco a caratteri invisibili che ho provato viene completamente annullato da una riga di normalizzazione dell'input. I variation selector no, perché sono codepoint significativi (presentazione emoji, varianti CJK) che NFKC non piega e non dovrebbe piegare.

Riprodotto su tre modelli, due domini:

modellodominioz di basedopo vs16_30tasso di modifica
gpt-oss-20bprosa45.030.7257%
gpt-oss-20bcodice37.240.6858%
Qwen3.8-27Bprosa35.50-0.6757%

La soglia è z = 2.33. Tutti e tre finiscono sotto di essa e vi restano dopo la normalizzazione (0.09, 0.45 e -0.78 rispettivamente). Il testo si presenta in modo identico a un lettore umano.

Il secondo risultato reale non richiede alcun attacco: il testo a bassa entropia è appena filigranato già di per sé. La generazione di codice di Qwen3.8-27B ha una baseline pulita di z = 4.31, già vicina alla soglia senza aver fatto nulla.

di cosa si tratta

Anthropic (e Google DeepMind prima di loro, con il paper SynthID-Text) filigranano il testo generato alterando il campionamento dei token con un torneo con chiave. Il segnale sta in quali token sono stati scelti, non in qualche carattere nascosto. Volevo sapere quanto fosse fragile di fronte a una persona motivata con un trova-e-sostituisci, così ho costruito il generatore più un rilevatore mean-g non addestrato e gli ho lanciato contro degli attacchi.

La soglia del rilevatore è z = 2.33 (tasso di falsi positivi dell'1%). Sopra quella soglia = filigrana rilevata. Ho generato testo filigranato, l'ho attaccato, ri-tokenizzato e valutato. Ogni tabella dei risultati contiene un controllo roundtrip (testo filigranato non attaccato) così puoi vedere che il rilevatore sta effettivamente funzionando in quella riga. Due volte nel corso di questo studio un bug ha fatto crollare ogni z a zero, e il controllo è stata l'unica cosa che l'ha scovato.

portata dell'attacco: cosa funziona davvero

La superficie d'attacco si divide nettamente in base alla categoria Unicode, che si è rivelata essere tutta la storia.

Funziona (categoria Mn, segni senza spaziatura):

Non funziona (categoria Cf, caratteri di formato):

I caratteri Cf sono pura formattazione senza contenuto semantico, quindi un normalizzatore può rimuoverli del tutto senza perdere nulla. I variation selector Mn portano significato reale nel testo emoji e CJK, quindi rimuoverli indiscriminatamente corromperebbe documenti legittimi. È questa asimmetria il motivo per cui una famiglia è difendibile e l'altra no.

La portata pratica: serve che circa il 20% o più dei caratteri venga toccato per spingere una baseline forte sotto la soglia, ma i caratteri inseriti sono invisibili, quindi il testo si legge normalmente a qualsiasi tasso di modifica. È verificato come visivamente identico, vedi src/fidelity_check.py. Quattro famiglie inseriscono solo caratteri che non renderizzano nulla; gli homoglyph sono l'eccezione onesta (dipendono dal font, non è garantito che siano invisibili).

cosa non funziona: le cose ovvie

La mia paura iniziale era quella banale: che i trattini emme, la sostituzione di "and" con "&" e la rimozione del markdown funzionassero e basta, e che la filigrana si rivelasse un teatro della sicurezza. Molte persone online presumono esattamente questo.

Non funziona. L'intera scala di modifiche superficiali su gpt-oss-20b, fino a 32k token:

Su tre modelli (0.8B, 4B, 20B = 294 celle), esattamente una cella ha superato la soglia: la cancellazione del 39% di ogni parola alla lunghezza più breve sul 4B. Questo non è un attacco, è fare a pezzi il documento.

Due cose mi hanno sorpreso:

  • Il numero di modifiche non predice il danno, la geometria delle modifiche sì. Rimuovere tutto il markdown (13.6% dei token) non ha fatto nulla; ha persino ottenuto un punteggio leggermente sopra la baseline. Iniettare spazi sparsi all'1.6% ha fatto 25 volte più danno per modifica. I marcatori markdown tendono a raggrupparsi, quindi le loro finestre di corruzione si sovrappongono e le lunghe sequenze di prosa tra di loro continuano a riprodurre il seed della filigrana intatto. Le modifiche sparse che desincronizzano il tokenizer colpiscono finestre nuove ogni volta.
  • La lunghezza aiuta il rilevatore, non l'attaccante. z cresce come sqrt(tokens). "Ingannarlo su un contesto lungo" è il contrario: 32k è il caso più difficile da attaccare, non il più facile.

Meccanismo completo e tabelle per singolo attacco in docs/FINDINGS.md.

Prova la versione interattiva → Veri campioni dello studio con un toggle prima/dopo, più un playground per eseguire la trasformazione dell'attacco sul tuo testo. Non ti dirà se un testo incollato a caso è davvero filigranato (servirebbe una chiave che non abbiamo), e lo dichiara; vedi site/ per lo script del generatore.

il risultato che non richiede alcun attacco

La filigrana si basa sull'incertezza per-token del modello. Dove il modello è sicuro del token successivo, il torneo non ha spazio per influenzarlo, quindi non entra alcun segnale. Questo significa che la marca è debole sul testo a bassa entropia, e il codice è a bassa entropia.

Qwen3.5-4B, prosa vs codice, campioni da 512 token, nessun attacco:

dominioentropiaz
prosa1.19 bits/tok11.1
codice0.55 bits/tok5.0

Il rapporto delle z è 0.45x, il rapporto dell'entropia è 0.46x: si muovono insieme, ed è il meccanismo che traspare. 3 campioni di codice su 8 sono scesi alla soglia di rilevamento o sotto di essa da soli. Il più estremo (un algoritmo spoglio, 0.2 bit/token) ha ottenuto 1.7, un mancato rilevamento.

Diventa più estremo su larga scala. Z di base senza alcun attacco:

modelloprosacodicerapporto
gpt-oss-20b45.0337.240.83
Qwen3.8-27B35.504.310.12

L'output di codice di Qwen3.8-27B è così basato su template che la filigrana pulita e non attaccata si assesta a z = 4.31, appena sopra la soglia di 2.33. Nessun avversario richiesto.

Dice questo: una singola soglia di confidenza su tutti i domini non è sicura, e i frammenti di codice brevi sono quasi impossibili da filigranare. Si generalizza a JSON, config, estrazione strutturata, boilerplate.

implicazioni difensive

Se distribuisci uno di questi rilevatori, normalizzare l'input ti porta per la maggior parte della strada, ma non tutta:

  1. Rimuovi i caratteri di categoria Cf. Elimina zero-width, bidi e le combinazioni. È questa la vittoria più grande.
  2. Piegatura NFKC. Gestisce nbsp e le forme di compatibilità.
  3. Rimuovi esplicitamente gli intervalli dei variation selector. NFKC non lo farà per te, ed è questa la falla attualmente aperta.
  4. Tieni una mappa dei confondibili Unicode (UTS-39) per gli homoglyph. Neanche questo NFKC lo fa.

I passi 3 e 4 sono quelli che un normalizzatore ingenuo si perde.

cosa c'è che non va / a cosa non sono arrivato

Per essere onesti sulle lacune.

  • I numeri del codice su 27B non sono informativi come risultato dell'attacco. La baseline non attaccata lì è z = 4.31, quindi non puoi dimostrare un attacco che batte un rilevatore già quasi cieco. Ho tenuto quelle righe ma le ho etichettate; il segnale significativo è la baseline, non i delta dell'attacco.
  • Se il risultato del codice sul 27B sia dovuto all'entropia o allo stile del modello resta irrisolto. Servirebbe una misurazione dell'entropia per-token come quella che ha avuto il 4B, che per quel modello non ho eseguito.
  • GLM-5.2 non ha prodotto alcun dato. Ho noleggiato un pod 8xA100 e ho incontrato cinque guasti infrastrutturali di fila (comando di download deprecato, rotture ABI di torch/torchvision, il modello che si caricava nella RAM dell'host invece che nelle GPU), ho bruciato ~$25 inclusi $19 su un pod rimasto inattivo perché mi sono fidato di un download che non è mai partito, e l'ho terminato senza nulla. Kimi-K3 non è mai stato tentato; a ~1.5TB anche quantizzato richiede 20+ A100. La questione della scala frontier è aperta.
  • Tre checkpoint quantizzati dalla community di Qwen3.8-27B non sono riusciti a caricarsi (FP8 che richiede un torch dtype che non abbiamo, due repack AWQ/compressed-tensors con mismatch di packing). L'ho invece eseguito in bf16 su un H100. Se stai riproducendo, salta i repack.
  • Il rilevatore è lo scorer mean-g non addestrato, non quello bayesiano addestrato del paper. Il rilevatore bayesiano sarebbe probabilmente più sensibile, quindi questi valori di z sono un limite inferiore, ma non l'ho misurato.
  • La mia affermazione sulla fedeltà degli homoglyph è "lettore tipico", non dimostrata. La а cirillica è di categoria Ll, quindi la sua invisibilità è una proprietà del font, non una garanzia Unicode.
  • n è piccolo, 2 documenti per cella per le scale, 8 campioni per dominio per l'entropia. Abbastanza per le dimensioni degli effetti qui (sono grandi), non abbastanza per barre di errore strette per singolo attacco.
  • Non fornisco una ricetta di evasione calibrata, ed è una scelta deliberata. Ogni attacco qui è riportato insieme al risultato della normalizzazione che lo sconfigge o no. Lo scopo era misurare dove sta la frontiera, non confezionare un bypass.

struttura

root@kitploit:~
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

come eseguirlo

root@kitploit:~
python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
root@kitploit:~
# 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 accetta prose, code o mixed. FAST_WM=1 usa un bridge di filigranatura numpy (più veloce su modelli a vocabolario piccolo con una CPU potente), FAST_WM=0 usa il processore GPU di HF (molto più veloce su modelli a vocabolario grande; su un H100 è stata la differenza tra 0% e 46% di utilizzo della GPU).

La filigranatura richiede l'intera distribuzione del token successivo, quindi passa attraverso transformers (CUDA nativo MXFP4, o MPS/CPU). Ollama e llama.cpp non possono farlo: non espongono i logits a generazione in corso. Su Apple Silicon, src/synthid_mlx.py collega la generazione MLX alla matematica della filigrana; è validato come bit-identico al riferimento HF.


il sogno, a quanto pare

(il meme che ha dato inizio a tutto. a quanto pare servono i variation selector, non un trova-e-sostituisci.)


Nota: ho usato molto Claude Code per l'implementazione e per rieseguire gli esperimenti su quattro macchine (un Mac, la mia 4090, una 3090 noleggiata e un H100). Il disegno degli esperimenti, gli attacchi che volevo provare e le scelte di inquadramento sono miei. Claude ha insistito per misurare ogni attacco contro la sua stessa difesa, ed è per questo che le tabelle stego hanno una colonna grezza e una normalizzata invece che solo quella grezza; è quello che ha trasformato "i caratteri invisibili la rompono" nel risultato reale, cioè che solo quelli di categoria Mn sopravvivono a un normalizzatore.

Scarica lo strumento
attaccocosa fatasso di modificasopravvive alla normalizzazione?
vs16_30variation selector dopo ~30% dei caratteri57%sì
vs16variation selector dopo ~10% dei caratteri23%sì (z 3.46)
vs_suppselector del piano supplementare (U+E0100+)24%sì (z 3.40)
homoglyphа cirillica per a latina (categoria Ll)9%sì, ma effetto debole
attaccoz grezzoz normalizzatoesito
zwsp_30-0.0935.68completamente annullato
combo0.9235.68completamente annullato
bidi24.3735.68completamente annullato
nbsp41.0446.51lo sposta appena
attaccotasso di modificaz @ 1kz @ 32k
roundtrip (controllo)0%25.7104.3
da trattino emme a trattino~0%26.4113.7
rimuovi tutto il markdown13.6%27.2103.3
da AmE a BrE + abbreviazioni1.3%~28~100
cancella il 40% di ogni parola38%4.925.4