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
nullorigin — Toolkit per la robustezza dei watermark AI, solo a scopo di ricerca: un reverse proxy locale rimuove C2PA/EXIF/XMP, Unicode, steganografia di immagini/audio, metadati OOXML/PDF e analizza Trojan Source. | Kitploit
Strumenti/GitHubGitHub/rakib-nyc/nullorigin
Analisi Statica del Codice (SAST)Proxy Web e IntercettazioneSteganografiaPrivacyApprendimento e FormazioneSicurezza dell'IAAttacco Avversario
GitHubrakib-nyc/nullorigin

nullorigin

Toolkit per la robustezza dei watermark AI, solo a scopo di ricerca: un reverse proxy locale rimuove C2PA/EXIF/XMP, Unicode, steganografia di immagini/audio, metadati OOXML/PDF e analizza Trojan Source.

Vedi Repository
44 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

NullOrigin 🛡️

Middleware universale per la provenienza AI e la sanificazione dei watermark Artefatto di ricerca — solo per la valutazione della robustezza del watermarking.

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


🔬 Solo uso di ricerca

NullOrigin è un artefatto di ricerca. Viene pubblicato per supportare lo studio accademico e indipendente della robustezza del watermarking, e per nessun altro scopo.

Gli schemi di watermarking sono affermazioni di sicurezza, e le affermazioni di sicurezza sono significative solo dopo che qualcuno ha provato a romperle. La letteratura che questo progetto implementa — Kirchenbauer et al. su KGW, Krishna et al. sugli attacchi di parafrasi, Boucher & Anderson su Trojan Source — esiste perché i ricercatori hanno pubblicato attacchi funzionanti affinché i difensori potessero misurare la robustezza reale invece di assumerla. È questa la tradizione a cui appartiene questo repository.

Usi previsti

  • Misurare quanto la rilevabilità di un watermark degradi sotto un attacco dichiarato
  • Riprodurre ed estendere i risultati di robustezza pubblicati
  • Valutare la perdita di metadati di provenienza nei propri documenti prima di condividerli
  • Verificare il codice sorgente per attacchi Trojan Source e omoglifi (CVE-2021-42574, CVE-2021-42694)
  • Insegnare come funzionano questi schemi e dove reggono

Non previsto e non supportato

  • Spacciare il lavoro generato come proprio dove una persona o un'istituzione ti ha chiesto di non farlo
  • Eludere i segnali di provenienza su contenuti che intendi travisare
  • Rimuovere l'attribuzione da opere che non sono tue
  • Aggirare qualsiasi policy di piattaforma, licenza o integrità accademica

Nulla di quanto scritto qui è un controllo tecnico su come il codice viene eseguito. È una dichiarazione dei termini con cui viene offerto e di ciò che il suo autore supporterà o meno. Il software è fornito "AS IS", senza garanzie di alcun tipo — vedi LICENSE.

Leggi Scopo e limiti onesti prima di trarre qualsiasi conclusione da un numero stampato da questo strumento. Diversi degli schemi presi di mira non possono essere verificati con un rilevatore pubblico, e il README lo dice esplicitamente piuttosto che suggerire il contrario.


Contenuti

  • Solo uso di ricerca
  • Scopo e limiti onesti
  • Fondamenti teorici
  • Installazione
  • Avvio rapido
  • Docker
  • Distribuzione oltre localhost
  • CLI
  • Benchmarking
  • Fedeltà semantica
  • Configurazione
  • Risoluzione dei problemi
  • Architettura
  • Test
  • Citazione e riutilizzo
  • Stato del progetto
  • Riferimenti
  • Nota legale e attribuzione

⚠️ Scopo e limiti onesti

Leggi questo prima di trarre conclusioni da qualsiasi numero stampato da questo strumento.

Informazioni sul rilevatore KGW

KGWStatisticalDetector è un'implementazione matematicamente fedele e autoconsistente dello schema green/red-list di Kirchenbauer et al. sui token di spazio bianco. Non è un decoder per il watermark di produzione di alcun fornitore — questi si basano su un segreto privato e il vocabolario BPE del modello stesso.

Il suo scopo è rendere il benchmark reale: KGWWatermarkEmbedder inserisce un watermark genuino, la pipeline lo attacca e il rilevatore corrispondente misura la riduzione effettiva. Questa è una misurazione vera dell'attacco contro questo schema. Non si trasferisce al watermark di un fornitore.


📖 Fondamenti teorici

Testo — green/red list KGW

Il vocabolario $V$ viene partizionato a ogni passo $t$ da un hash inizializzato sul contesto precedente:

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

in una lista verde $G_t$ di dimensione $\gamma|V|$ e una lista rossa $R_t$. Un bias $\delta > 0$ viene aggiunto ai logit verdi:

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

La rilevazione conta i successi verdi. Sotto $H_0$ sono $\text{Binomial}(T, \gamma)$, quindi:

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

con $z > 4.0$ ($p < 3\times10^{-5}$) segnalato come sintetico.

Perché la parafrasi lo attacca: il watermark vive interamente nelle transizioni n-gram locali. Riscrivere la forma superficiale con un modello non marcato re-inizializza ogni posizione. Questo è l'attacco di robustezza standard nella letteratura sul watermarking.

Perché la lunghezza è importante: $z$ cresce come $\sqrt{T}$. Un passaggio di 100 token a una frazione verde di 0,70 raggiunge solo $z \approx 3,9$ — sotto la soglia. La rilevazione richiede qualche centinaio di token, e così anche i fixture di benchmark significativi.

Immagine — C2PA e embedding nel dominio delle frequenze

  • C2PA / JUMBF: manifest firmati nei segmenti JPEG APP11, chunk PNG tEXt/iTXt, o box c2pa WebP/AVIF. Poiché la firma copre i dati dei pixel, la ricodifica da un buffer di campioni nudo lo rimuove senza dover analizzare affatto JUMBF.
  • SynthID-Image: spostamenti nei coefficienti DCT/DWT. Attaccato tramite soft-thresholding delle sottobande di dettaglio ad alta frequenza.
  • Tree-Ring: un pattern a simmetria circolare nel latente iniziale della diffusione, che sopravvive come struttura coerente nella fase di Fourier. Attaccato randomizzando la fase in anelli a media frequenza preservando la magnitudine — motivo per cui l'immagine rimane visivamente identica.

Audio — AudioSeal / SynthID-Audio

Modulazione di fase sotto-soglia e aggiunte spettrali a bassa ampiezza. Attaccate tramite randomizzazione della fase sopra la fondamentale del parlato, spostamento di notch band-stop in bande non critiche e ri-quantizzazione psicoacustica.


📦 Installazione

Requisiti

Python3.10, 3.11 o 3.12
Sistema operativoLinux, macOS (Intel e Apple Silicon), Windows tramite WSL2
OpzionaleOllama o qualsiasi server compatibile con OpenAI —

Dal sorgente```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:~
### Extra opzionali```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]"

Senza [nli], il gate di fedeltà si basa esclusivamente sugli invarianti — un controllo comunque reale, ma cieco agli scambi di ruolo. Vedi Fedeltà semantica.

Verifica l'installazione```bash

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

root@kitploit:~
---

## 🚀 Avvio rapido

### 1. Configura un modello di riscrittura locale

La rimozione della filigrana dal testo richiede un modello locale senza filigrana. Senza uno, NullOrigin rimuove
i caratteri invisibili ma **lascia intatta la filigrana statistica** — e lo dichiara.```bash
ollama serve                    # in a separate terminal
ollama pull llama3.2:3b         # or any instruct model you prefer

Stai usando un modello diverso? Punta NullOrigin su di esso:```bash export NULLORIGIN_PARAPHRASER_MODEL=qwen3:4b export NULLORIGIN_PARAPHRASER_TIMEOUT=900 # reasoning models are slow

root@kitploit:~
### 2. Avvia il proxy```bash
nullorigin run

Please provide the Markdown content to translate.```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. Punta il tuo client verso di esso```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"}]}'

Streaming (SSE) e Gemini (/v1beta/models/...) sono gestiti allo stesso modo. L'header x-nullorigin-provider seleziona l'upstream e viene rimosso prima dell'inoltro; i tuoi header di autenticazione passano senza modifiche.


🐳 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:~
Lo stack Compose esegue NullOrigin più un sidecar Ollama su una rete bridge privata.
Il container proxy si lega a `0.0.0.0` — corretto all'interno di un container — e solo la porta 8080 è
pubblicata sul tuo host.

Immagine standalone:```bash
docker build -t nullorigin:1.0.0 .
docker run -d -p 8080:8080 \
  -e NULLORIGIN_PARAPHRASER_BACKEND=none \
  nullorigin:1.0.0

Comandi utili:```bash docker compose logs -f nullorigin docker compose down # stop docker compose down -v # stop and delete the Ollama model volume

root@kitploit:~
---

## 🔒 Distribuzione oltre localhost

**NullOrigin per impostazione predefinita usa `127.0.0.1` e rifiuta di associarsi a un'interfaccia pubblica senza un
token di telemetria.** Inoltra le credenziali API upstream, quindi questa è una scelta deliberata:```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

Per esporlo correttamente:```bash export NULLORIGIN_TELEMETRY_TOKEN=$(openssl rand -hex 32) nullorigin run --host 0.0.0.0 --port 8080

root@kitploit:~
poi mettilo dietro nginx, Caddy o Traefik che forniscono **terminazione TLS**, **limitazione della frequenza** e un **livello di autenticazione**.

### Modello di minaccia

NullOrigin è un **proxy inverso locale che inoltra le credenziali API del tuo upstream**. Questo singolo fatto determina la sua postura di sicurezza.

| Controllo | Predefinito | Perché |
| --- | --- | --- |
| Indirizzo di bind | `127.0.0.1` | Solo loopback; un bind pubblico viene rifiutato a meno che non sia impostato un token di telemetria o non venga passato `--allow-public-bind`. |
| `/telemetry`, `/telemetry/reset` | Aperti su loopback | Protetti da `X-NullOrigin-Token`, confrontato a tempo costante, quando `proxy.telemetry_token` è impostato. |
| `/health` | Sempre aperto | I probe dei container ne hanno bisogno; espone versione e motori abilitati, nessun segreto. |
| Dimensione del corpo della richiesta | 100 MiB | Il proxy bufferizza i body per inoltrarli; input più grandi vengono rifiutati con `413`. |
| Buffer SSE | 1 MiB | Un upstream che non termina mai un frame viene svuotato, non bufferizzato indefinitamente. |
| Utente del container | non-root | Il proxy non necessita di privilegi elevati. |

Limitazioni note, per scelta progettuale e non difetti:

* **Niente TLS.** Inoltra `Authorization` e `x-api-key` così come sono su HTTP in chiaro. Mettilo dietro un reverse proxy che termina HTTPS su qualsiasi rete non affidabile.
* **Nessuna autenticazione sul percorso del proxy.** Chiunque possa raggiungere la porta può usarlo come proxy, con le proprie credenziali — NullOrigin non memorizza né inietta chiavi.
* **Nessuna limitazione della frequenza.** Applicala al reverse proxy.
* **Le credenziali non vengono mai persistite.** Nessuna chiave API viene scritta su disco o nei log; la telemetria conta solo richieste ed eventi di sanitizzazione.
* La verifica TLS dell'upstream resta attiva e i redirect non vengono seguiti.

Per segnalare un problema di sicurezza, invia un'email a **[email protected]** con `[NullOrigin Security]` nell'oggetto.

Telemetria con token impostato:```bash
curl -H "X-NullOrigin-Token: $NULLORIGIN_TELEMETRY_TOKEN" http://localhost:8080/telemetry

/health non è mai soggetto a gate, quindi i probe dei container continuano a funzionare.


🛠️ 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:~
### Formati supportati

| Tipo | Estensioni | Note |
| --- | --- | --- |
| **Immagini** | `.png` `.jpg` `.jpeg` `.jfif` `.webp` `.tif` `.tiff` `.bmp` `.gif` `.ico` `.avif` `.jp2` | Tutte le modalità PIL (RGB, RGBA, L, LA, P, 1, I;16, CMYK, YCbCr). GIF/WebP animati e TIFF multipagina conservano ogni fotogramma e i relativi tempi. Le immagini sotto i 64px mantengono le dimensioni esatte. |
| **Audio** | `.wav` `.wave` | int a 8/16/32 bit, float a 32 bit; da mono a multicanale; qualsiasi frequenza di campionamento. I file di lunghezza zero vengono mantenuti invariati. |
| **Documenti** | `.docx` `.docm` `.dotx` `.pptx` `.pptm` `.xlsx` `.xlsm` | Tutti e tre i dialetti OOXML. Le sequenze di testo vengono sanificate in corpo, intestazioni, piè di pagina, note a piè di pagina, note e stringhe condivise; i metadati `docProps` vengono cancellati; ogni altra parte viene copiata byte per byte. |
| **PDF** | `.pdf` | Dizionario `/Info`, pacchetto XMP, allegati incorporati e JavaScript rimossi; pagine, testo e geometria preservati. I file protetti da password vengono rifiutati. Vedere l'avvertenza di seguito. |
| **Codice sorgente** | `.py` `.js` `.ts` `.go` `.rs` `.java` `.c` `.cpp` `.rb` `.php` `.sh` `.sql` + altri 50 | Scansione Trojan Source e omoglifi. **Niente NFKC, niente parafrasi** — vedere sotto. |
| **Testo** | qualsiasi altra cosa decodificabile | UTF-8, UTF-8 BOM, UTF-16, UTF-32, CP1252, Latin-1 — rilevati automaticamente e **riscritti nella stessa codifica**. |

Tutto il resto viene **rifiutato con indicazioni specifiche** piuttosto che letto come UTF-8 e corrotto — `.mp3` rimanda a `ffmpeg -i in.mp3 out.wav`, i legacy `.doc`/`.ppt`/`.xls` a un nuovo salvataggio come OOXML. Un file rifiutato non produce mai output.

Verificato su un corpus di 69 file che copre ogni formato sopra: **59 elaborati correttamente, 10 rifiutati in modo pulito, zero crash, zero output corrotti.**

### Il codice è tenuto fuori dal riscrittore

Le risposte dell'assistente mescolano prosa e codice in un'unica stringa. Passare l'intero contenuto a un modello di parafrasi riscrive il codice insieme alla prosa — e lo z-score diminuisce in entrambi i casi, quindi nulla a valle se ne accorge.

Le risposte vengono quindi segmentate prima che qualsiasi cosa venga riscritta:

| Segmento | Trattamento |
| --- | --- |
| Prosa | Pulita a livello Unicode, poi riscritta |
| Blocchi delimitati (``` e ~~~) | Caratteri invisibili e bidi rimossi. **Niente NFKC, mai riscritti.** |
| Span di codice inline `` `code` `` | Lo stesso |

Questo vale anche nel percorso di streaming, dove un delimitatore si apre in un delta e si chiude parecchi delta dopo. Un delta che attraversa il confine viene diviso per riga, così la ``` di chiusura e la prosa successiva vengono trattate in modo diverso. Un delimitatore non chiuso fallisce in modo sicuro: la parte rimanente viene protetta, non riscritta.

Disattivare con `text.protect_code_blocks: false` se si vuole il vecchio comportamento.

### File di codice sorgente: una scansione di sicurezza, non una rimozione di filigrane

**Non esiste alcuna filigrana nel codice sorgente generato dall'IA.** Nessun fornitore filigrana l'output del codice e non esiste alcun rilevatore pubblico. Chiunque affermi di rimuoverne una ti sta vendendo qualcosa.

Ciò che il codice sorgente *ha* davvero è una superficie d'attacco reale e pubblicata:

* **Trojan Source** ([CVE-2021-42574](https://nvd.nist.gov/vuln/detail/CVE-2021-42574), Boucher & Anderson 2021) — i caratteri di controllo bidirezionali riordinano il modo in cui il codice viene *visualizzato* senza cambiare come *compila*. Un revisore approva un programma; il compilatore ne costruisce un altro.
* **Identificatori omoglifi** ([CVE-2021-42694](https://nvd.nist.gov/vuln/detail/CVE-2021-42694)) — la `а` cirillica al posto della `a` latina crea due nomi che vengono resi in modo identico.```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⁩⁦":

Dopo la purga, la riga recita if access_level != "user // Check if admin": — il "commento" era dentro la stringa fin dall'inizio.

Tre cose che il percorso del codice deliberatamente non fa, perché il percorso testuale generico faceva tutte e tre e ciascuna è un bug sul sorgente:

  1. Nessuna normalizzazione NFKC. Riscrive i valori dei letterali stringa: "Hello" diventa "Hello", "office" diventa "office". Questo cambia ciò che un programma confronta, sottopone a hash e trasmette.
  2. Nessuna parafrasi. Inviare codice a un modello di riscrittura produce codice che non viene eseguito.
  3. Gli omoglifi vengono segnalati, non ripiegati. Ripiegare una а cirillica fonde due identificatori che il compilatore attualmente tratta come distinti — cambiando silenziosamente il comportamento. La gravità è MEDIUM solo per token a script misti (totаl), la firma effettiva dell'attacco; una parola scritta interamente in un altro script è testo straniero ordinario e riceve INFO. Puoi attivare l'opzione con --fold-homoglyphs-in-code una volta che li hai esaminati.

inspect --json emette per ogni riscontro gravità, riga, colonna e codepoint, quindi si integra nella CI come gate pre-commit o PR.

PDF: cosa viene rimosso e cosa no

Rimosso, in modo verificabile: il dizionario /Info (Author, Title, Subject, Keywords, Creator, Producer, CreationDate, ModDate), il pacchetto XMP in /Root/Metadata, gli allegati di file incorporati e JavaScript a livello di documento. Pagine, testo e geometria di pagina vengono preservati esattamente; l'operazione è idempotente e stabile a livello di byte.

Rilevati ma NON rimossi: i caratteri invisibili all'interno dei flussi di contenuto delle pagine. Il PDF disegna il testo glifo per glifo tramite una codifica specifica del font — uno spazio a larghezza zero in un font CID-keyed è un indice di glifo a due byte, non un U+200B letterale — quindi una riscrittura generica corromperebbe il layout invece di pulirlo. inspect riporta il conteggio; purge stampa un avviso invece di restare in silenzio, perché il silenzio potrebbe essere interpretato come "non ce n'erano". Per rimuoverli, estrai il testo, esegui nullorigin purge su di esso e rigenera il PDF.

--strip-annotations è disponibile ma disattivata per impostazione predefinita: le annotazioni includono collegamenti e campi modulo, non solo commenti, quindi rimuoverle cambia il comportamento del documento.

La tipografia non è una filigrana

Trattini em, virgolette ricurve ed ellissi sono normale output di un word processor. NullOrigin li preserva per impostazione predefinita e li segnala separatamente dai riscontri reali, perché appiattirli degrada un documento senza sanificare nulla. Usa --flatten-typography se vuoi specificamente un output ASCII.

I confondibili cross-script sono diversi — una о cirillica a metà parola in testo inglese non ha alcun uso legittimo — e questi vengono ripiegati per impostazione predefinita.

--verify riporta le misurazioni prima/dopo invece di affermare il successo:```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:~
Se il backend non è raggiungibile, viene segnalato un avviso su stderr — un fallback silenzioso sembrerebbe identico a una sanificazione riuscita.

---

## 📊 Benchmarking```bash
nullorigin build-datasets
nullorigin benchmark

Ogni valore viene misurato sul posto: il testo viene marcato con KGWWatermarkEmbedder, eseguito attraverso la pipeline reale e rivalutato con il detector corrispondente. Il runner termina con codice non zero quando le soglie non vengono soddisfatte e ne spiega il motivo.

Soglie (dalla direttiva del progetto):

MetricaObiettivo
Z-score post-sanitizzazione$\lvert z\rvert \le 1.5$
Similarità semantica$\ge 0.92$
SSIM dell'immagine$\ge 0.95$
PSNR dell'immagine$\ge 36$ dB

Risultati misurati

Sezione di testo completo su datasets/text/watermarked_kgw.json, riscritto tramite Ollama (qwen3:4b) su un MacBook serie M (~150 s per passaggio):```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:~
Ogni campione filigranato è passato da rilevato a non rilevato. Nota `kgw_003` a
z = 1.271 — sotto la soglia ma il più vicino ad essa, che è la forma onesta di questo
attacco: è statistico, non una garanzia.

Media, misurata sulle immagini di test:```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

Entrambe le soglie delle immagini vengono superate (SSIM ≥ 0.95, PSNR ≥ 36 dB). I numeri varieranno con il modello, l'hardware e il passaggio.

Fedeltà semantica: un calo dello z-score non è prova di significato preservato

Una riscrittura che cambia un fatto ottiene un punteggio identico a una fedele sulla metrica del watermark. Il controllo ovvio per questo non funziona, e non funziona nemmeno quello meno ovvio. Misurato su sei casi di deriva più un controllo fedele:

La sovrapposizione lessicale è invertita. Ogni modifica che distrugge il significato ha ottenuto un punteggio più alto della riscrittura fedele, perché una buona parafrasi condivide pochi n-grammi con la sua fonte, mentre una corrotta ne condivide quasi tutti.

Il coseno di embedding non lo risolve. Tre dei sei casi corrotti superano una soglia di 0.92. "Alice paid Bob" e "Bob paid Alice" sono la stessa bag of words e ottengono 0.985; "must not disable" → "must disable" ottiene 0.947. Gli embedding di frase codificano la relazione tematica, non la verità.

Quindi la fedeltà è verificata su due livelli, e nessuno dei due è il coseno:

  1. Invarianti — numeri, conteggio delle negazioni, forza modale, forza dei quantificatori, URL, email, identificatori, entità nominate. Deterministici, senza dipendenze e spiegabili (negation count changed: 1 → 0). I modali e i quantificatori sono confrontati per classe di significato, quindi may → might supera e may → must fallisce. Insensibile agli scambi di ruolo in cui ogni entità sopravvive.
  2. Implicazione bidirezionale — il significato è preservato se e solo se ogni testo implica l'altro. Cattura ciò che il conteggio non può, inclusi gli scambi di ruolo, e l'asimmetria è diagnostica (la rimozione dell'attenuazione ha ottenuto a⇒b 0.991, b⇒a 0.011). Richiede nullorigin[nli]; senza di esso il limite viene riportato, non nascosto.

È un gate, non un report

Misurare la deriva dopo il fatto non aiuta se il testo danneggiato è già stato restituito. Un controllo fallito riprova a una temperatura più bassa — la deriva è guidata dalla temperatura — e dopo il budget di tentativi restituisce l'originale, con ok=False e il motivo.```yaml text: fidelity: enabled: true max_retries: 2 temperature_step: 0.25 use_nli: true nli_threshold: 0.5

root@kitploit:~
Questo significa anche che attacco e rischio condividono un unico controllo: alzare la temperatura abbassa lo
z-score *e* aumenta il tasso di drift. Il benchmark li riporta insieme, piuttosto che come
controlli indipendenti.

### Altre metriche

* **Perplexity** — vera PPL GPT-2 con `torch` + `transformers`, altrimenti
  `unigram_entropy_proxy`, contrassegnata come approssimativa e **non** confrontabile con la PPL pubblicata.
* **Similarità coseno** viene ancora riportata come `mean_cosine_or_lexical`, solo come riferimento.
  Non è più un criterio pass/fail, per i motivi indicati nella tabella sopra.

## ⚙️ Configurazione

Ordine di risoluzione, dalla precedenza più bassa alla più alta:

1. Valori predefiniti integrati
2. `nullorigin.yaml` (cercato in `./`, `../`, `/app/` o `$NULLORIGIN_CONFIG`)
3. Variabili d'ambiente `NULLORIGIN_*`
4. Flag CLI espliciti

### Impostazioni principali

| Impostazione | Predefinito | Note |
| --- | --- | --- |
| `proxy.host` | `127.0.0.1` | Loopback. Un bind pubblico viene rifiutato senza un token di telemetria. |
| `proxy.port` | `8080` | |
| `proxy.default_provider` | `openai` | Usato quando non viene inviato l'header `x-nullorigin-provider`. |
| `proxy.telemetry_token` | `""` | Protegge `/telemetry` e `/telemetry/reset`. |
| `proxy.max_request_bytes` | `104857600` | 100 MiB; i body più grandi ricevono `413`. |
| `text.paraphraser.backend` | `ollama` | `none` \| `ollama` \| `openai_compatible` \| `llama_cpp` \| `lexical`. `none` lascia intatta la filigrana statistica. `lexical` non richiede un modello ma è un attacco molto più debole. |
| `text.clean_unicode` | `true` | Rimozione di caratteri a larghezza zero e del blocco Tags. |
| `text.fold_homoglyphs` | `true` | Confondibili cirillici/greci convertiti in ASCII. |
| `text.stream_window_tokens` | `40` | Delta bufferizzati prima che uno span di streaming venga riscritto. |
| `media.crop_mode` | `trim` | `trim` sposta le coordinate senza ricampionare; `resample` ripristina le dimensioni esatte ma costa circa SSIM 0.81 / PSNR 31 dB anche con un ritaglio dello 0.5%; `none` disabilita il passaggio geometrico. |
| `audio.low_cut_hz` | `800.0` | La fase al di sotto di questo valore viene preservata per l'intelligibilità. |

### Variabili d'ambiente```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

🩺 Risoluzione dei problemi

model 'llama3.2:3b' not found Il modello configurato non è stato scaricato. Esegui ollama list per vedere cosa hai, poi ollama pull llama3.2:3b oppure imposta NULLORIGIN_PARAPHRASER_MODEL su un modello che hai già.

WARNING: ollama backend unavailable (ReadTimeout) La riscrittura ha superato text.paraphraser.timeout_seconds (predefinito 120 s). I modelli di ragionamento come qwen3 impiegano regolarmente 150 s+ per paragrafo su CPU. Aumentalo: export NULLORIGIN_PARAPHRASER_TIMEOUT=900, oppure usa un modello instruct più piccolo.

nullorigin benchmark esce con 1 e pass_no_detection: FAIL Funziona come previsto. Nessun backend di riscrittura era raggiungibile, quindi è stato eseguito solo il livello unicode e la filigrana statistica è sopravvissuta. Avvia Ollama, oppure imposta il backend su lexical per un confronto senza dipendenze.

semantic_check: INCONCLUSIVE Previsto senza l'extra [metrics]. Vedi Onestà delle metriche.

Error: Refusing to bind 0.0.0.0 without a telemetry token Intenzionale. Vedi Distribuzione oltre localhost.

Multiple top-level packages discovered in a flat-layout Sei su un checkout vecchio. pyproject.toml imposta un elenco esplicito di pacchetti; fai pull dell'ultima versione.

I test async segnalano UsageError per un plugin async mancante Deliberato — senza uno, pytest segnala i test async def come superati senza eseguirne l'await. pip install -e ".[dev]".

Docker: curl: (7) Failed to connect subito dopo compose up L'healthcheck ha un periodo di avvio di 10 s. Attendi, poi controlla docker compose logs nullorigin.


🏗️ Architettura```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:~
### Layout```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

🧪 Test```bash

pytest -q

root@kitploit:~
384 test. La suite copre il parser dei frame SSE contro confini di chunk avversari, il ciclo di vita dello streaming proxy, ogni modalità immagine PIL, SSIM sia rispetto a un valore in forma chiusa sia a un'implementazione di riferimento brute-force, e la rilevabilità delle filigrane nel dataset.

I test asincroni falliscono in modo evidente se non è installato alcun plugin asincrono, piuttosto che essere saltati silenziosamente.

---

## 📖 Citazioni e riuso

Concesso in licenza sotto Apache-2.0, che consente l'uso, la modifica e la ridistribuzione a condizione che vengano mantenuti l'avviso di copyright e l'attribuzione a **Muhammad Rakibul Islam**. Vedere [LICENSE](https://github.com/rakib-nyc/nullorigin/blob/HEAD/LICENSE) e [NOTICE](https://github.com/rakib-nyc/nullorigin/blob/HEAD/NOTICE).

Se questo lavoro supporta una pubblicazione, si prega di citarlo come:```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}
}

Questa repository è pubblicata come artefatto di ricerca completo e non accetta pull request. Sei libero di farne un fork secondo i termini della licenza. Domande e risultati sono benvenuti via email a [email protected].


🗺️ Stato del progetto

Versione 1.0.0. La suite è completa rispetto alle sue specifiche e completamente testata, con questi limiti noti:

  • L'efficacia contro SynthID, Tree-Ring e AudioSeal non è verificabile qui — non esiste un rilevatore pubblico per misurarla. Le perturbazioni sono implementate; l'affermazione non viene fatta.
  • La deriva semantica è controllata da invarianti più NLI opzionale. Senza [nli], gli scambi di ruolo che preservano ogni entità sono indistinguibili, e il rapporto lo dichiara.
  • La latenza con un modello di ragionamento locale (~150 s per brano) rende il percorso testuale inadatto all'uso interattivo. Un modello instruct più piccolo è molto più veloce.
  • Nessuna TLS e nessuna autenticazione delle richieste — per progettazione; eseguilo dietro un reverse proxy.

Vedi CHANGELOG.md per la cronologia delle release.


📚 Riferimenti

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

📜 Nota legale e attribuzione

  • Autore e creatore: Muhammad Rakibul Islam
  • Contatto: [email protected]
  • Licenza: Apache License, Version 2.0

Questa repository è un artefatto di livello di ricerca rilasciato per ricerca statistica, valutazione della privacy, benchmarking della robustezza delle watermark e test di resilienza crittografica.```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:~
**NESSUNA GARANZIA.** IL SOFTWARE VIENE FORNITO "COSÌ COM'È", SENZA ALCUN TIPO DI GARANZIA,
ESPRESSA O IMPLICITA.
Scarica lo strumento
LivelloCosa fa realmente
Caratteri invisibiliPienamente efficace. I payload con larghezza zero, controllo bidi, selettori di variante e blocco Unicode Tags vengono rimossi completamente, con un conteggio riportato. I confondibili omoglifi tra scritture diverse (cirillico/greco resi come ASCII) vengono normalizzati.
Metadati del documento (.docx)Pienamente efficace. Autore, ultimo editor, numero di revisioni, timestamp, modello e versione dell'applicazione vengono cancellati da docProps, con la formattazione preservata byte per byte.
C2PA / EXIF / XMPPienamente efficace. L'immagine viene ricostruita da campioni di pixel grezzi in un contenitore nuovo, quindi i manifest JUMBF firmati e tutti i metadati spariscono. Verificato tramite test su fixture etichettati.
Watermark statistico KGWDipende interamente dal backend di riscrittura. Senza un modello locale configurato, il watermark statistico sopravvive — lo strumento lo dice esplicitamente piuttosto che suggerire il contrario.
SynthID-Text / SynthID-Image / Tree-RingNon verificabile qui. Questi usano chiavi private e decoder proprietari. NullOrigin applica le perturbazioni descritte dalla letteratura, ma non viene fatta alcuna affermazione che sconfiggano i rilevatori reali, perché non esiste un rilevatore pubblico con cui misurarli.
AudioSeal / SynthID-AudioNon verificabile qui, per lo stesso motivo.
richiesto per il de-watermarking del testo
OpzionaleDocker 20.10+ con Compose v2
casolexical_f1coseno di embeddingNLI bidirezionale
negazione omessa0.700.77 ✓0.000 ✓
numero 5 → 500.820.81 ✓0.000 ✓
scambio entità/ruolo0.810.985 ✗0.000 ✓
quantificatore all → some0.880.91 ✓0.000 ✓
attenuazione rimossa0.270.953 ✗0.011 ✓
"must not" → "must"0.830.947 ✗0.000 ✓
riscrittura fedele0.330.931 ✓0.998 ✓