Arquitectura

El motor que solo puede leer y responder

El motor de análisis hace exactamente dos cosas: leer el modelo y responder en localhost. Nada más — y lo impone el núcleo del sistema operativo, no nuestro código.

~6 min de lectura · Arquitectura

Por qué este componente es el más encerrado

Cuando PoisonZero analiza un cambio on-device, el motor es el componente que lee texto controlado por el atacante — el mismo memory-diff que alguien puede haber diseñado para escaparse. Por eso lo tratamos como la superficie más expuesta del sistema y lo encerramos en consecuencia: es el componente más encerrado que entregamos. El objetivo de diseño es directo: un exploit del motor debe convertirse en un fallo de proceso sin consecuencias, no en una cabeza de puente. Y si el motor cae, el daemon no se encoge de hombros: revierte el cambio sospechoso (fail-closed).

Fíjate en la separación deliberada. El daemon corre privilegiado a propósito — como servicio root (LaunchDaemon / systemd) —, porque tiene que vigilar archivos de memory que no le pertenecen y revertirlos en su sitio; ese trabajo no puede hacerse sin privilegios. El motor es justo lo contrario: no toca nada de lo que el daemon protege, solo lee la entrada bajo sospecha, así que se reduce a casi nada. Esa asimetría es la arquitectura: el componente más expuesto es el más encerrado, y romperlo no alcanza al daemon privilegiado.

El motor lee, por oficio, entrada controlada por el atacante. Asumimos que puede romperse — y construimos de modo que romperlo no consiga nada.

macOS: la sandbox del núcleo

En macOS el motor se ejecuta dentro de la sandbox del núcleo (Seatbelt / sandbox-exec) con un perfil deny-by-default: todo está prohibido salvo que se permita explícitamente. El perfil viaja con el daemon y reside como un archivo auditable junto al modelo — puedes leer exactamente qué se le permite hacer al motor. Si el servicio corre como root, el motor mismo cae a un usuario sin privilegios (nobody).

Verificado en vivo en Apple Silicon — y la sandbox no cuesta latencia medible: una evaluación en caliente corre en torno a 1,1 segundos de cualquier modo.

Linux: Landlock, impuesto por el núcleo

En Linux la jaula es Landlock, un módulo de seguridad del núcleo (LSM), de nuevo deny-by-default. El motor puede:

Las conexiones salientes las rechaza el núcleo con «permission denied» — antes de que un solo byte salga del sistema. Esto no es una promesa en nuestro código; se demuestra sobre un núcleo real en CI en cada build. Sin escritura en disco, sin lanzar procesos ajenos, sin egress de red.

«Leer solo el archivo del modelo» solo es cierto si el motor realmente no necesita nada más del disco. Por eso el motor de Linux está compilado totalmente estático contra musl — sin cargador dinámico, sin libc compartida — en ambas arquitecturas (amd64 y arm64). Un binario enlazado de forma normal tendría que leer y ejecutar /lib64/ld-linux y la libc del sistema al arrancar, forzando esas rutas a la allowlist; el motor estático lee exactamente un archivo y ejecuta exactamente un binario, él mismo.

En Linux el núcleo deniega la conexión saliente del motor antes de que un byte salga de la máquina. La garantía vive por debajo de nuestro código — donde la entrada del atacante no llega.

Windows: token restringido + Job Object

En Windows el motor corre bajo un token restringido con un Job Object del núcleo — y está en vivo y verificado, fail-closed exactamente como macOS y Linux. El token se crea de modo que se le quitan todos los privilegios (solo queda el inocuo privilegio de «notificar al cambiar»), y el proceso corre con integridad baja (low integrity), así que no puede escribir objetos de integridad normal. El Job Object deja al motor ejecutar exactamente un procesono puede lanzar un hijo, el núcleo lo bloquea — y limita su memoria. Sigue enlazando solo a localhost, sin conexión saliente.

Verificado en vivo en GitHub Actions windows-latest: el lanzamiento de procesos hijos lo bloquea el núcleo, y el motor real de Windows carga y evalúa correctamente bajo las restricciones de token y Job. (Una etapa aún más estricta con AppContainer está en la hoja de ruta; el perfil actual ya se entrega, en vivo y fail-closed.)

Estrictamente fail-closed: sin sandbox, sin análisis

En todas las plataformas la regla es la misma y es estricta: si la sandbox no está disponible, el motor no arranca. No hay degradación silenciosa a una ejecución sin sandbox. En su lugar, los cambios sospechosos se revierten en vez de pasar sin evaluar. El análisis on-device sin la jaula del núcleo simplemente no ocurre.

Es un límite honesto — y ahí está el punto. «Fail-closed» significa: sin Landlock (o Seatbelt), no hay análisis on-device en ese host. Preferimos protegerte revirtiendo antes que exponer el componente más expuesto al atacante sin su jaula. El límite es la función.

Qué requiere de tus máquinas

macOS: nada especial — la sandbox del núcleo siempre está ahí.

Linux: un núcleo ≥ 5.13 con Landlock activo. Eso cubre Ubuntu ≥ 22.04, Debian ≥ 12 y RHEL ≥ 9.6 de fábrica; en otras distribuciones lo habilitas con el parámetro de arranque lsm=landlock,…. Dentro de contenedores, el perfil seccomp por defecto de Docker bloquea las syscalls de Landlock — ahí hace falta un perfil ajustado.

Windows: nada especial — el token restringido y el Job Object son funciones estándar del núcleo.

Para entornos donde no se puede habilitar Landlock, hay una alternativa opt-in: evaluación en la nube como respaldo remoto. La protección se mantiene; el flujo de datos se documenta de forma transparente en lugar de ocultarse.

La versión corta

El diseño completo, incluido el contrato de egress verificable, está en el whitepaper técnico. Relacionado: Por qué gana el fail-closed y Memory Poisoning.

Un análisis que no pueden volver contra ti.

PoisonZero ejecuta el motor on-device en una jaula impuesta por el núcleo — leer el modelo, responder en localhost, nada más.

Sign me up

Seguir leyendo: Por qué gana el Fail-closed · ¿Qué es el Memory Poisoning? · Claude, MCP y Tool-Poisoning

Todos los artículos