Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Herramientas/GitHubGitHub/aloshdenny/claude-awm
EsteganografíaPrivacidadAprendizaje AutomáticoSeguridad de IAAtaque Adversario
GitHubaloshdenny/claude-awm

claude-awm

Evade las marcas de agua de texto de LLM inyectando selectores de variación Unicode; incluye el generador SynthID, el detector mean-g, defensas de normalización y experimentos de entropía.

Ver Repositorio
173hace 4 díasAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

claude-awm: ¿puedes eliminar una marca de agua de texto SynthID editando el texto?

Hola, soy Alosh ✌🏻

Sí, pero solo funciona una familia de ataques, y no es la que todo el mundo supone.

Los selectores de variación Unicode (categoría Mn, U+FE00 a U+FE0F y U+E0100 a U+E01EF) llevan al detector por debajo del umbral y se quedan allí. Cualquier otro ataque de caracteres invisibles que probé queda totalmente revertido por una sola línea de normalización de entrada. Los selectores de variación no, porque son puntos de código con significado (presentación de emojis, variantes CJK) que NFKC no plegará ni debería plegar.

modelodominioz basetras vs16_30tasa de edición
gpt-oss-20bprosa45.030.7257%
gpt-oss-20bcódigo37.240.6858%
Qwen3.8-27Bprosa35.50-0.6757%

El umbral es z = 2.33. Los tres aterrizan por debajo y se mantienen por debajo tras la normalización (0.09, 0.45, -0.78 respectivamente). El texto se muestra de forma idéntica para un lector humano.

El segundo hallazgo real no necesita ningún ataque: el texto de baja entropía apenas está marcado de partida. La generación de código de Qwen3.8-27B tiene una línea base limpia de z = 4.31, ya cerca del umbral sin hacerle nada.

qué es esto

Anthropic (y Google DeepMind antes que ellos, en el artículo SynthID-Text) marca el texto generado sesgando el muestreo de tokens con un torneo con clave. La señal reside en qué tokens se eligieron, no en ningún carácter oculto. Quería saber cuán frágil es eso frente a una persona motivada con un buscar y reemplazar, así que construí el generador junto con un detector mean-g no entrenado y le lancé ataques.

El umbral del detector es z = 2.33 (1% de tasa de falsos positivos). Por encima = marca de agua detectada. Generé texto marcado, lo ataqué, lo re-tokenicé y lo puntué. Cada tabla de resultados incluye un control roundtrip (texto marcado sin atacar) para que puedas ver que el detector realmente funciona en esa fila. Dos veces durante este estudio un error hizo que todos los z colapsaran a cero, y el control fue lo único que lo detectó.

alcance del ataque: qué funciona realmente

La superficie de ataque se divide claramente por categoría Unicode, que resultó ser toda la historia.

Funciona (categoría Mn, marcas sin espaciado):

No funciona (categoría Cf, caracteres de formato):

Los caracteres Cf son formato puro sin contenido semántico, así que un normalizador puede eliminarlos por completo sin perder nada. Los selectores de variación Mn tienen significado real en texto con emojis y CJK, por lo que eliminarlos de forma indiscriminada corrompería documentos legítimos. Esa asimetría es la razón por la que una familia es defendible y la otra no.

El alcance práctico: esto necesita que se toque aproximadamente un 20% o más de los caracteres para empujar una línea base fuerte por debajo del umbral, pero los caracteres insertados son invisibles, así que el texto se lee con normalidad a cualquier tasa de edición. Está verificado que es visualmente idéntico, ver src/fidelity_check.py. Cuatro familias insertan solo caracteres que no renderizan nada; los homoglifos son la excepción honesta (dependen de la fuente, no se garantiza que sean invisibles).

lo que no funciona: lo obvio

Mi miedo inicial era el aburrido: que los em-dashes, el cambio de "and" a "&" y eliminar el markdown funcionarían sin más, y la marca de agua resultaría ser teatro de seguridad. Mucha gente en internet asume exactamente eso.

No funciona. Toda la escalera de edición superficial sobre gpt-oss-20b, hasta 32k tokens:

En tres modelos (0.8B, 4B, 20B = 294 celdas), exactamente una celda cruzó el umbral: eliminar el 39% de cada palabra en la longitud más corta en el 4B. Eso no es un ataque, es destrozar el documento.

Dos cosas me sorprendieron:

  • La cantidad de ediciones no predice el daño; la geometría de las ediciones sí. Eliminar todo el markdown (13.6% de los tokens) no hizo nada; incluso puntuó ligeramente por encima de la línea base. Inyectar espacios sueltos al 1.6% hizo 25 veces más daño por edición. Los marcadores de markdown están agrupados, así que sus ventanas de corrupción se solapan y los largos tramos de prosa entre ellos siguen reproduciendo la semilla de la marca de agua intacta. Las ediciones dispersas que desincronizan el tokenizador golpean ventanas nuevas cada vez.
  • La longitud ayuda al detector, no al atacante. z crece como sqrt(tokens). "Engañarlo en un contexto largo" es al revés: 32k es el caso más difícil de atacar, no el más fácil.

Mecanismo completo y tablas por ataque en docs/FINDINGS.md.

Prueba la versión interactiva → Muestras reales del estudio con un conmutador de revelado antes/después, además de un campo de pruebas para ejecutar la transformación del ataque sobre tu propio texto. No te dirá si un texto pegado arbitrario está realmente marcado (eso requiere una clave que no tenemos), y así lo dice; ver site/ para el script del generador.

el hallazgo que no necesita ningún ataque

La marca de agua se apoya en la incertidumbre por token del modelo. Cuando el modelo está seguro sobre el siguiente token, el torneo no tiene margen para sesgarlo, así que no entra ninguna señal. Eso significa que la marca es débil en texto de baja entropía, y el código es de baja entropía.

Qwen3.5-4B, prosa vs. código, muestras de 512 tokens, sin ningún ataque:

dominioentropíaz
prosa1.19 bits/tok11.1
código0.55 bits/tok5.0

La proporción de z es 0.45x, la proporción de entropía es 0.46x; se mueven juntas, lo que deja ver el mecanismo. 3 de las 8 muestras de código cayeron al umbral de detección o por debajo por sí solas. La más ajustada (un algoritmo escueto, 0.2 bits/token) obtuvo 1.7, un fallo.

Se vuelve más extremo a escala. Línea base de z sin ningún ataque:

modeloprosacódigoproporción
gpt-oss-20b45.0337.240.83
Qwen3.8-27B35.504.310.12

La salida de código de Qwen3.8-27B está tan basada en plantillas que la marca de agua limpia y sin atacar se sitúa en z = 4.31, apenas por encima del umbral de 2.33. No se requiere adversario.

Lo que dice: un único umbral de confianza entre dominios no es seguro, y los fragmentos de código cortos están cerca de ser imposibles de marcar. Se generaliza a JSON, config, extracción estructurada y texto repetitivo.

conclusión defensiva

Si distribuyes uno de estos detectores, normalizar la entrada te lleva la mayor parte del camino, pero no todo:

  1. Elimina los caracteres de la categoría Cf. Acaba con los de ancho cero, los bidi y las combinaciones. Este es el gran logro.
  2. Aplica el pliegue NFKC. Maneja nbsp y las formas de compatibilidad.
  3. Elimina explícitamente los rangos de selectores de variación. NFKC no lo hará por ti, y esta es la brecha actualmente abierta.
  4. Mantén un mapa de confusables Unicode (UTS-39) para homoglifos. NFKC tampoco hará eso.

Los pasos 3 y 4 son los que un normalizador ingenuo pasa por alto.

qué hay de malo en esto / a lo que no llegué

Siendo honesto sobre las carencias.

  • Los números de código del 27B son poco informativos como resultado de ataque. La línea base sin atacar allí es z = 4.31, así que no puedes demostrar un ataque que venza a un detector que ya está casi ciego. Mantuve esas filas pero las etiqueté; la señal significativa es la línea base, no los deltas del ataque.
  • Si el resultado de código del 27B es entropía o estilo del modelo sigue sin resolverse. Necesita una medición de entropía por token como la que recibió el 4B, que no ejecuté para ese modelo.
  • GLM-5.2 produjo cero datos. Alquilé un pod de 8xA100 y me topé con cinco fallos de infraestructura seguidos (comando de descarga obsoleto, rupturas ABI de torch/torchvision, el modelo cargándose en la RAM del host en lugar de en las GPUs), quemé ~$25 incluyendo $19 en un pod que estuvo inactivo porque confié en una descarga que nunca comenzó, y lo terminé sin nada. Kimi-K3 nunca se intentó; con ~1.5 TB incluso cuantizado necesita 20+ A100. La pregunta a escala fronteriza sigue abierta.
  • Tres checkpoints cuantizados de la comunidad de Qwen3.8-27B fallaron al cargar (FP8 pidiendo un torch dtype que no tenemos, dos reempaquetados AWQ/compressed-tensors con desajustes de empaquetado). En su lugar lo ejecuté en bf16 en un H100. Si vas a reproducirlo, sáltate los reempaquetados.
  • El detector es el puntuador mean-g no entrenado, no el bayesiano entrenado del artículo. El detector bayesiano probablemente sería más sensible, así que estos valores de z son un mínimo, pero no lo medí.
  • Mi afirmación de fidelidad de los homoglifos es "lector típico", no probada. La а cirílica es de categoría Ll, así que su invisibilidad es una propiedad de la fuente, no una garantía de Unicode.
  • n es pequeño: 2 documentos por celda para las escaleras, 8 muestras por dominio para la entropía. Suficiente para los tamaños de efecto de aquí (son grandes), no suficiente para barras de error ajustadas por ataque.
  • No proporciono una receta afinada de evasión, y es a propósito. Cada ataque se informa junto con el resultado de normalización que lo vence o no. El objetivo era medir dónde está la frontera, no empaquetar un bypass.

estructura

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

cómo ejecutarlo

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 acepta prose, code o mixed. FAST_WM=1 usa un puente de marca de agua numpy (más rápido en modelos de vocabulario pequeño con una CPU potente), FAST_WM=0 usa el procesador GPU de HF (mucho más rápido en modelos de vocabulario grande; en un H100 esta fue la diferencia entre 0% y 46% de utilización de GPU).

El marcado de agua necesita la distribución completa del siguiente token, así que se ejecuta a través de transformers (MXFP4 nativo de CUDA, o MPS/CPU). Ollama y llama.cpp no pueden hacerlo; no exponen los logits a mitad de generación. En Apple Silicon, src/synthid_mlx.py conecta la generación MLX con las matemáticas de la marca de agua; está validado como bit-idéntico a la referencia de HF.


el sueño, supuestamente

(el meme que lo empezó todo. resulta que necesitas selectores de variación, no un buscar y reemplazar).


Nota: usé Claude Code intensamente para la implementación y para re-ejecutar experimentos en cuatro máquinas (una Mac, mi propia 4090, una 3090 alquilada y un H100). El diseño del experimento, los ataques que quería probar y las decisiones de encuadre son míos. Claude insistió en medir cada ataque contra su propia defensa, que es por lo que las tablas de esteganografía tienen una columna bruta y una normalizada en lugar de solo la bruta; eso es lo que convirtió "los caracteres invisibles la rompen" en el hallazgo real, que es que solo los de la categoría Mn sobreviven a un normalizador.

Descargar herramienta
ataquequé hacetasa de edición¿sobrevive a la normalización?
vs16_30selector de variación tras ~30% de los caracteres57%sí
vs16selector de variación tras ~10% de los caracteres23%sí (z 3.46)
vs_suppselectores de plano suplementario (U+E0100+)24%sí (z 3.40)
homoglyphа cirílica por a latina (categoría Ll)9%sí, pero efecto débil
ataquez brutoz normalizadoveredicto
zwsp_30-0.0935.68totalmente revertido
combo0.9235.68totalmente revertido
bidi24.3735.68totalmente revertido
nbsp41.0446.51apenas lo mueve
ataquetasa de ediciónz @ 1kz @ 32k
roundtrip (control)0%25.7104.3
em-dash a guion~0%26.4113.7
eliminar todo el markdown13.6%27.2103.3
AmE a BrE + abreviaturas1.3%~28~100
eliminar el 40% de cada palabra38%4.925.4