Diwall MCP

Español
Descargar v0.0.2

¿Cómo configurar mi equipo para que un modelo no lea mis contraseñas?

La configuración de su equipo decide, no el servidor. Los tres niveles (intransigente, normal, imprudente) lado a lado con lo que cierra cada uno y lo que cuesta, luego los pasos en orden con la salida real de cada comando y el comando que comprueba el resultado.

Contenido

La respuesta corta: la configuración de su equipo decide

Que un modelo pueda leer sus contraseñas se resuelve con la configuración de su equipo, no con el servidor. El servidor cierra las vías que puede cerrar: el valor de una credencial no aparece nunca en un resultado de herramienta, en el diario ni en una línea de comandos; solo se escribe en el origen al que está ligada; un pago, una eliminación o un cambio de secreto esperan su confirmación. Un modelo que además tiene un shell es otra cosa. Llega a todo lo que llega su cuenta: si funciona bajo la cuenta que guarda su directorio cifrado, lista los archivos que hay allí, habla con el navegador por su puerto de depuración y reescribe el perfil al que obedece el servidor. Ninguna comprobación dentro del servidor puede rechazar lo que el sistema permite.

Una regla escrita en un archivo de configuración la puede modificar un modelo con un shell. Un rechazo del sistema operativo, porque el archivo pertenece a otra cuenta, no. Usted elige cuánto quiere que el sistema rechace, entre tres niveles: intransigente, normal e imprudente (desaconsejado). Los pasos los construyen en orden inverso, desde el equipo que usted tiene hasta el más estricto. Esta página pone los tres lado a lado y da, para cada uno, los pasos en orden, cada comando con su salida real, y la comprobación que dice dónde está su equipo.

En resumen: solo el nivel intransigente cierra la captura de lo que usted escribe y sudo. El nivel normal cierra el directorio cifrado, el perfil del navegador, el puerto de depuración y el diario, pero no la cuenta bajo la que funciona el modelo. El nivel imprudente no cierra nada: es el estado de un equipo en el que no se ha elegido nada.

Los tres niveles lado a lado

Un nivel es una propiedad del equipo, no un ajuste del servidor. Depende de qué cuenta guarda el directorio cifrado, el navegador y el servidor, y de bajo qué cuenta funciona el modelo.

NivelBajo su cuentaBajo diwall-mcpBajo agent
Intransigentesu pantalla, las ventanas de confirmación, la administraciónel directorio cifrado, el perfil del navegador, el navegador, el servidorel cliente MCP y el modelo
Normalel cliente MCP y el modelo, su pantalla, las ventanas de confirmaciónel directorio cifrado, el perfil del navegador, el navegador, el servidornada
Imprudente (desaconsejado)todonadanada
NivelCierraDeja abiertoCuesta
Intransigentelas diez vías: nueve por el núcleo, la vía 4 por el servidorningunauna cuenta más (agent), en cuyo directorio personal acaba todo lo que el modelo escribe
Normallas vías 1, 2, 3, 5, 6 y 8 por el núcleo, la vía 4 por el servidorlas vías 7, 9 y 10una cuenta (diwall-mcp), una unidad de systemd y una regla de cortafuegos
Imprudente (desaconsejado)nada por el núcleonueve vías de diez; la décima no tiene objetonada
  • Intransigente traslada el cliente y el modelo a una tercera cuenta. No llega ni a su pantalla, ni a sus archivos de arranque, ni a sus derechos de administrador.
  • Normal traslada el directorio cifrado, el navegador y el servidor a una segunda cuenta. Detiene a un modelo descuidado o engañado y la inyección corriente, que pasan por el directorio cifrado. No detiene a un modelo concebido para hacer daño: ese funciona bajo su cuenta y llega a su shell y a sudo.
  • Imprudente es el equipo que da la instalación si no hace nada más: el modelo y el directorio cifrado comparten una sola cuenta. El núcleo no cierra nada; solo se sostienen reglas (la configuración del cliente, las comprobaciones del servidor).

Las diez vías que un modelo puede tomar hacia un secreto

Una vía está cerrada por el núcleo cuando el sistema rechaza lo que el modelo intente, cerrada por el servidor cuando el código del servidor la rechaza y el modelo no puede cambiar ni ese código ni su configuración, y abierta en cualquier otro caso. El nivel de un equipo es el de su vía más abierta.

VíaLo que intenta un modelo con un shellIntransigenteNormalImprudente (desaconsejado)
1. Leer el directorio cifrado: credenciales, diario, capturas, descargasls y cat en el punto de montajenúcleonúcleoabierta
2. Leer el perfil del navegador: las cookies de las sesiones abiertasleer el directorio del perfilnúcleonúcleoabierta
3. Dirigir el navegador sin el servidor, por su puerto de depuraciónconectarse al puerto 9222núcleonúcleoabierta
4. Hacerse pasar por el navegador: escuchar en el puerto antes que él, para que el servidor se conecte y escriba allí una contraseñaabrir un oyente en el puerto y luego llamar a statusservidorservidorsin objeto
5. Cambiar lo que el servidor permite: perfil del operador, unidad, comando del servidorescribir el perfil y la unidadnúcleonúcleoabierta
6. Borrar o reescribir su rastro en el diarioescribir en el directorio del diarionúcleonúcleoabierta
7. Responder a la ventana de confirmación en su lugarxdotool, /dev/uinput, el socket de su pantallanúcleoabiertaabierta
8. Leer la memoria del servidor, del navegador o de gocryptfs/proc/<pid>/mem, gdb -pnúcleonúcleoabierta
9. Capturar una contraseña que usted escribeescribir un alias en los archivos de arranque de su shell, leer los eventos del tecladonúcleoabiertaabierta
10. Convertirse en administradorsudo -n true, sudo -l, inyectar pulsaciones en su terminalnúcleoabiertaabierta

Las vías 7, 9 y 10 siguen abiertas en el nivel normal porque el modelo funciona bajo la cuenta que posee su pantalla, sus archivos de arranque y sus derechos de sudo. En el nivel intransigente la pantalla rechaza la cuenta del modelo, los archivos de arranque y los eventos del teclado le están cerrados, y no tiene sudo. Las vías 7 y 9, y el comando xhost que se usa más abajo, dependen del servidor gráfico de su sesión. Se midieron dos veces: en X11, en una sesión KDE, y en Wayland, en una sesión GNOME; la sección sobre una sesión Wayland, más abajo, dice qué es distinto allí.

Lo que mantiene todo nivel

El servidor hace esto en todos los niveles, porque su código lo hace:

  • el valor de una credencial no está nunca en un resultado de herramienta, en el diario ni en una línea de comandos;
  • una credencial solo se escribe en su propio origen;
  • un pago, una eliminación o un cambio de secreto esperan su confirmación.

Estas comprobaciones protegen de una fuga por las herramientas. No protegen de un modelo con un shell bajo la cuenta del directorio cifrado, y por eso existen los niveles. Un nivel protege el valor de un secreto, no el uso de una sesión abierta en el navegador dedicado: el modelo puede usar esa sesión, dentro de los límites de la lista roja, en todos los niveles (Límites, Conectar un cliente MCP).

Comprobar su nivel: el informe de isolation

mcp-server-diwall-browser-setup isolation se ejecuta desde la cuenta del modelo. Prueba cada una de las diez vías con el ensayo de la tabla de arriba, no escribe nada, no pide ninguna contraseña, no lanza ningún sudo y no lee ningún contenido del servidor. Para cada vía dice cerrada por el núcleo, cerrada por el servidor, abierta, sin objeto o no medible desde aquí, y luego el nivel alcanzado. El subcomando llega con la versión 0.0.2 del servidor.

  • Sin argumento toma diwall-mcp como cuenta del servidor si esa cuenta existe, y su cuenta en caso contrario. isolation seguido de un nombre de cuenta toma esa cuenta en su lugar; --port PORT nombra otro puerto de depuración; --json imprime los veredictos para un script.
  • Una vía que necesita el directorio cifrado no es medible mientras el directorio no esté montado, y la vía 6 no es medible antes de que el servidor haya funcionado una vez, porque el directorio del diario aún no existe: el informe enumera esa vía y no la cuenta como cerrada.
  • La vía 4 la prueba el código instalado del servidor sobre una tabla simulada en la que escucha la cuenta del modelo, no con un oyente real. La vía 10 se prueba sin sudo: grupos, reglas de sudoers legibles y el interruptor de la inyección en el terminal. Una regla que solo root puede leer es invisible desde la cuenta del modelo, y el informe lo dice.

Sobre los comandos y sus salidas

Los comandos se ejecutaron en dos equipos con Debian 13, un nivel tras otro, y luego se deshicieron en orden inverso: uno con una sesión KDE sobre X11, que dio las salidas de los tres niveles, y otro con una sesión GNOME 48.7 sobre Wayland, que volvió a ejecutar los mismos comandos y dio las salidas de la sección sobre una sesión Wayland. Las salidas están copiadas de esas ejecuciones, con sustituciones: su cuenta se escribe alice, su directorio personal ~ y la carpeta de pruebas del equipo Wayland /var/tmp/test. Las líneas de progreso de apt y los párrafos explicativos que el asistente de instalación muestra alrededor de las peticiones de contraseña se han omitido. Los comandos del sistema se ejecutaron con LC_ALL=C para que sus mensajes se lean igual en todas partes; los suyos siguen su idioma, y los números de versión que se ven son los de lo que estaba instalado ese día. Los mensajes del asistente de instalación están en francés. Las líneas de traza que un shell escribe para un comando ejecutado en un subshell ($$) se han omitido de las salidas Wayland.

Todos los comandos usan los mismos valores de ejemplo: el operador es la cuenta con la que usted ha iniciado sesión (alice en las salidas, $(id -un) en los comandos), la cuenta del servidor es diwall-mcp, la cuenta del modelo es agent, el directorio cifrado se guarda en /var/lib/diwall-mcp y el puerto de depuración es 9222.

use_pty. Debian 13 trae Defaults use_pty en /etc/sudoers: el archivo del paquete sudo 1.9.16 lo tiene en la línea 15. Los dos equipos lo tenían. El equipo Wayland tiene una regla más, para otro programa, y nada más difiere del archivo del paquete:

$ dpkg-query -W '-f=${Version}\n' sudo
1.9.16p2-3+deb13u2
$ mkdir -p /var/tmp/test/apt-sudo
$ cd /var/tmp/test/apt-sudo
$ apt-get download sudo
0% [Working]
Get:1 http://deb.debian.org/debian trixie/main amd64 sudo amd64 1.9.16p2-3+deb13u2 [2086 kB]
0% [1 sudo 9772 B/2086 kB 0%]
100% [Working]
Fetched 2086 kB in 0s (8236 kB/s)
$ dpkg-deb --fsys-tarfile sudo_1.9.16p2-3+deb13u2_amd64.deb
$ tar -xO ./etc/sudoers
$ grep -n use_pty
15:Defaults	use_pty
$ diff /dev/fd/63 /dev/fd/62
6a7
> %alice ALL=(ALL) NOPASSWD:/usr/bin/veracrypt

Poner un nivel en marcha, desde el equipo de partida

Los pasos de abajo siguen el orden en que se construye un nivel: cada uno se suma al anterior, de modo que la cuenta agent no puede existir antes que diwall-mcp, ni diwall-mcp antes que el equipo de partida. Terminan en el nivel intransigente, el que responde al título; deténgase en el normal solo si acepta que el modelo conserve su pantalla, sus archivos de arranque y sudo.

El equipo de partida, imprudente (desaconsejado)

Lo que cierra: nada por el núcleo. Lo que deja abierto: todas las vías salvo la vía 4, que no tiene objeto porque el modelo ya lo posee todo. Coste: ninguno.

Así está un equipo tras la instalación y el primer arranque, sin ningún paso más. Un modelo con un shell bajo su cuenta lista el directorio cifrado y lee las credenciales, el diario y las descargas; lee las cookies de sus sesiones abiertas en el perfil del navegador; dirige el navegador por su puerto de depuración sin pasar por el servidor; reescribe el perfil del operador y la unidad que inicia el servidor; borra su rastro en el diario; responde a la ventana de confirmación en su lugar; lee la memoria del servidor y del navegador; captura una contraseña que usted escribe mediante un alias en los archivos de arranque de su shell; y se convierte en administrador si su cuenta pertenece al grupo sudo. El informe al final de este nivel muestra nueve vías abiertas de diez. Las comprobaciones del servidor siguen valiendo para lo que pasa por sus herramientas; no valen contra un shell.

Paso 1. Instale el paquete y las herramientas de los niveles siguientes, desde el directorio que contiene el archivo del paquete. El subcomando isolation llega con la versión 0.0.2: tome ese paquete o uno posterior, sea cual sea el número de versión que muestre la salida de abajo.

sudo apt install ./mcp-server-diwall-browser_*_all.deb socat nftables x11-xserver-utils chromium
Note, selecting 'mcp-server-diwall-browser' instead of './mcp-server-diwall-browser_0.0.2-1_all.deb'
socat is already the newest version (1.8.0.3-1+deb13u1).
nftables is already the newest version (1.1.3-1).
x11-xserver-utils is already the newest version (7.7+11).
chromium is already the newest version (156.0.8078.73-1~deb13u1).
Installing:
  mcp-server-diwall-browser
Summary:
  Upgrading: 0, Installing: 1, Removing: 0, Not Upgrading: 0
  Download size: 0 B / 318 kB
  Space needed: 755 kB / 268 GB available
Continue? [Y/n] y
Setting up mcp-server-diwall-browser (0.0.2-1) ...
mcp-server-diwall-browser installed.

Paso 2. Cree el directorio cifrado con su perfil del operador y luego inicie el navegador dedicado. create pide la contraseña dos veces, luego una vez más para abrir el volumen, y muestra una clave maestra una sola vez: anótela en papel. Se usa Chromium porque Google Chrome abre, en su primer arranque con un perfil nuevo, una ventana de condiciones de uso y mantiene cerrado el puerto de depuración hasta que se aceptan.

mcp-server-diwall-browser-setup create --browser chromium
mcp-server-diwall-browser-setup browser
Volume chiffré gocryptfs : ~/Vaults/Main.enc, ouvert sur ~/Vaults/Main.
Choose a password for protecting your files.
Password:
Repeat:

Your master key is:

    <master key>

The gocryptfs filesystem has been created successfully.
Password:
Filesystem mounted and ready.
Volume ouvert. Profil écrit : ~/.config/mcp-server-diwall-browser/profile.json.
Navigateur lancé (processus 13553) sur le profil du volume, détaché de ce terminal. Ouvrez-y vous-même vos sessions sur les sites.

Paso 3. Llame al servidor una vez, como lo haría su cliente, para que exista su diario. La sonda envía los tres mensajes del protocolo, espera, y conserva de la respuesta de status el directorio cifrado y el navegador.

{ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"status","arguments":{}}}'; sleep 6; } | mcp-server-diwall-browser 2>/dev/null | tail -n 1 | grep -o 'encrypted_directory[^}]*}\|browser\\": {[^}]*}'
encrypted_directory\": {\"state\": \"mounted\"}
browser\": {\"attached\": true, \"product\": \"Chrome\", \"version\": \"156.0.8078.73\"}

Paso 4. Lea el informe. Nueve vías están abiertas y la vía 4 no tiene objeto, así que el nivel es imprudente.

mcp-server-diwall-browser-setup isolation
Essai des dix voies depuis le compte « alice » (uid 1002) ; le serveur tourne sous « alice » (uid 1002).
Rien n'est écrit, aucun mot de passe n'est demandé, aucun sudo n'est lancé, aucun contenu du serveur n'est lu.

 1. Lire le répertoire chiffré : ouverte
    le point de montage ~/Vaults/Main se liste depuis ce compte
 2. Lire le profil du navigateur : ouverte
    le dossier du profil du navigateur se voit depuis ce compte
 3. Piloter le navigateur par son port de débogage : ouverte
    la connexion à 127.0.0.1:9222 aboutit
 4. Se faire passer pour le navigateur : sans objet
    le serveur tourne sous ce compte : le modèle a déjà tout
 5. Changer ce que le serveur s'autorise : ouverte
    ce compte écrit dans ~/.config/mcp-server-diwall-browser
 6. Effacer ou réécrire sa trace dans le journal : ouverte
    ce compte écrit dans le dossier du journal
 7. Répondre à la fenêtre de confirmation : ouverte
    l'écran :0 accepte une connexion de ce compte
 8. Lire la mémoire du serveur, du navigateur ou de gocryptfs : ouverte
    ce compte ouvre la mémoire du processus 1753 de « alice »
 9. Capter un mot de passe que l'opérateur tape : ouverte
    ce compte écrit dans ~/.bashrc, que le shell de « alice » lit à chaque ouverture
10. Devenir administrateur : ouverte
    ce compte est du groupe « sudo » : il devient administrateur, avec un mot de passe que la voie 9 capte, ou sans lui si une règle l'en dispense

Niveau atteint : inconscient (déconseillé)

Nivel normal: el servidor en una segunda cuenta

Lo que cierra por el núcleo: las vías 1, 2, 3, 5, 6 y 8. Por el servidor: la vía 4. Lo que deja abierto: las vías 7, 9 y 10. Coste: la cuenta diwall-mcp, una unidad de systemd y una regla de cortafuegos; las descargas y las capturas están en el directorio cifrado de diwall-mcp, que usted lee con sudo -u diwall-mcp (el montaje no tiene allow_other, de modo que también se rechaza a root); para sacar un archivo de ese directorio, vea el párrafo que sigue al paso 9.

Paso 1. Cierre el volumen del equipo de partida. close detiene primero el navegador.

mcp-server-diwall-browser-setup close
Fermeture du navigateur avant le démontage.
Volume fermé : ~/Vaults/Main.

Paso 2. Cree la cuenta del servidor. No tiene contraseña, ni sudo, ni más grupo que el suyo; adduser la pone en users, y el segundo comando la saca de él.

sudo adduser --disabled-password --gecos "" diwall-mcp
sudo gpasswd -d diwall-mcp users
id diwall-mcp
usermod: no changes
Removing user diwall-mcp from group users
uid=1000(diwall-mcp) gid=1000(diwall-mcp) groups=1000(diwall-mcp)

Paso 3. Cree el directorio cifrado bajo esa cuenta, fuera de su directorio personal, para que el rechazo de la vía 1 venga del montaje y no del modo de un directorio. El asistente pide la contraseña igual que en el equipo de partida.

sudo install -d -m 755 -o diwall-mcp -g diwall-mcp /var/lib/diwall-mcp
sudo -iu diwall-mcp mcp-server-diwall-browser-setup create --crypt-dir /var/lib/diwall-mcp/Main.enc --mount-dir /var/lib/diwall-mcp/Main --browser chromium
Volume chiffré gocryptfs : /var/lib/diwall-mcp/Main.enc, ouvert sur /var/lib/diwall-mcp/Main.
Choose a password for protecting your files.
Password:
Repeat:

Your master key is:

    <master key>

The gocryptfs filesystem has been created successfully.
Password:
Filesystem mounted and ready.
Volume ouvert. Profil écrit : ~/.config/mcp-server-diwall-browser/profile.json.

Paso 4. Dé a diwall-mcp acceso a su pantalla, que dura hasta que se cierre su sesión, y luego inicie su navegador. La ventana se abre en su pantalla. DISPLAY=:0 es la pantalla de su sesión: echo $DISPLAY se lo dice. En una sesión Wayland, xhost abre XWayland, el servidor X que GNOME inicia para las aplicaciones que no hablan Wayland, y DISPLAY es la pantalla de XWayland (:1 en el equipo medido: :0 era el servidor de la pantalla de inicio de sesión); la sección sobre una sesión Wayland, más abajo, da las salidas. Este acceso es el único sitio donde la frontera se abre a propósito: la cuenta del servidor puede teclear en su pantalla, y no solo abrir las ventanas de confirmación. Es aceptable porque todo nivel confía en el código del servidor y trata al modelo como el atacante.

xhost +SI:localuser:diwall-mcp
sudo -iu diwall-mcp env DISPLAY=:0 mcp-server-diwall-browser-setup browser
localuser:diwall-mcp being added to access control list
Navigateur lancé (processus 14123) sur le profil du volume, détaché de ce terminal. Ouvrez-y vous-même vos sessions sur les sites.

Paso 5. Escriba el puente: un socket de systemd que su cuenta puede abrir y un servicio que inicia un servidor por conexión bajo diwall-mcp. SocketGroup es el grupo de la cuenta que ejecuta el cliente.

sudo tee /etc/systemd/system/mcp-server-diwall-browser.socket >/dev/null <<EOF
[Unit]
Description=Bridge to the browser MCP server: socket of the model account

[Socket]
ListenStream=/run/mcp-server-diwall-browser/mcp.sock
Accept=yes
SocketUser=root
SocketGroup=$(id -un)
SocketMode=0660
DirectoryMode=0755

[Install]
WantedBy=sockets.target
EOF
sudo tee /etc/systemd/system/mcp-server-diwall-browser@.service >/dev/null <<'EOF'
[Unit]
Description=Browser MCP server, one connection (%i)

[Service]
User=diwall-mcp
WorkingDirectory=~
Environment=DISPLAY=:0
ExecStart=/usr/bin/mcp-server-diwall-browser
StandardInput=socket
StandardOutput=socket
StandardError=journal
NoNewPrivileges=yes
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now mcp-server-diwall-browser.socket
stat -c '%A %U %G %n' /run/mcp-server-diwall-browser/mcp.sock
Created symlink '/etc/systemd/system/sockets.target.wants/mcp-server-diwall-browser.socket' -> '/etc/systemd/system/mcp-server-diwall-browser.socket'.
srw-rw---- root alice /run/mcp-server-diwall-browser/mcp.sock

Paso 6. Pida al servidor su status a través del puente, con la sonda del equipo de partida.

{ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"status","arguments":{}}}'; sleep 6; } | socat - UNIX-CONNECT:/run/mcp-server-diwall-browser/mcp.sock | tail -n 1 | grep -o 'encrypted_directory[^}]*}\|browser\\": {[^}]*}'
encrypted_directory\": {\"state\": \"mounted\"}
browser\": {\"attached\": true, \"product\": \"Chrome\", \"version\": \"156.0.8078.73\"}

Paso 7. Cierre el puerto de depuración a toda cuenta salvo diwall-mcp. El rechazo admin-prohibited hace que una conexión falle de inmediato con No route to host, un error que un puerto cerrado nunca da, de modo que la regla se distingue de un navegador que no está en marcha. El puerto es el browser.debug_port del perfil. nftables.service carga la regla en cada arranque.

sudo install -d /etc/nftables.d
sudo tee /etc/nftables.d/diwall-mcp.nft >/dev/null <<'EOF'
table inet diwall_mcp {
  chain output {
    type filter hook output priority 0; policy accept;
    oifname "lo" tcp dport 9222 meta skuid != "diwall-mcp" reject with icmpx type admin-prohibited
  }
}
EOF
echo 'include "/etc/nftables.d/diwall-mcp.nft"' | sudo tee -a /etc/nftables.conf
sudo nft -c -f /etc/nftables.conf
sudo systemctl reload nftables
systemctl is-enabled nftables
include "/etc/nftables.d/diwall-mcp.nft"
enabled

En un equipo donde nftables.service está desactivado (systemctl is-enabled nftables responde disabled), reload falla con nftables.service is not active, cannot reload y la regla no se carga. No inicie el servicio antes de leer /etc/nftables.conf: sus propias reglas se aplican en cuanto arranca, y el archivo del equipo medido rechaza por defecto las conexiones entrantes y no tiene regla para el puerto SSH. Cargue en su lugar la tabla sola; dura hasta el próximo arranque:

$ systemctl is-active nftables
inactive
$ sudo nft -f /etc/nftables.d/diwall-mcp.nft
$ sudo nft list ruleset
table inet diwall_mcp {
	chain output {
		type filter hook output priority filter; policy accept;
		oifname "lo" tcp dport 9222 meta skuid != 1001 reject with icmpx admin-prohibited
	}
}
$ systemctl is-active nftables
inactive

Paso 8. Pruebe tres vías a mano desde su cuenta (la cuenta del modelo en este nivel). La vía 3 la rechaza la regla y diwall-mcp sigue conectándose; la vía 1 la rechaza el montaje; la vía 10 depende de sus reglas de sudo.

bash -c 'exec 3<>/dev/tcp/127.0.0.1/9222'
sudo -u diwall-mcp bash -c 'exec 3<>/dev/tcp/127.0.0.1/9222' && echo "diwall-mcp connects"
ls /var/lib/diwall-mcp/Main
sudo -n true && echo "sudo without a password: yes"
bash: connect: No route to host
bash: line 1: /dev/tcp/127.0.0.1/9222: No route to host
diwall-mcp connects
ls: cannot access '/var/lib/diwall-mcp/Main': Permission denied
sudo without a password: yes

La línea sudo without a password: yes es lo que la sonda encontró en la cuenta medida, no un ajuste que haya que obtener. Donde esa línea no aparece, la vía 10 no está cerrada por eso: un sudo que pide contraseña sigue abierto mientras la vía 9 pueda capturar la contraseña que usted escribe. La línea la escribe el echo del comando cuando sudo -n true tiene éxito, lo que exige una regla NOPASSWD: en una cuenta que no la tiene, sudo responde sudo: a password is required, la línea no se escribe y el código de salida es 1 (salidas en la sección sobre una sesión Wayland).

Paso 9. Lea el informe desde su cuenta.

mcp-server-diwall-browser-setup isolation
Essai des dix voies depuis le compte « alice » (uid 1002) ; le serveur tourne sous « diwall-mcp » (uid 1000).
Rien n'est écrit, aucun mot de passe n'est demandé, aucun sudo n'est lancé, aucun contenu du serveur n'est lu.

 1. Lire le répertoire chiffré : fermée par le noyau
    le noyau refuse ce compte au point de montage (/var/lib/diwall-mcp/Main) : le montage n'a pas d'accès pour un autre compte
 2. Lire le profil du navigateur : fermée par le noyau
    le noyau refuse ce compte au dossier du profil, qui est dans le volume
 3. Piloter le navigateur par son port de débogage : fermée par le noyau
    le noyau écarte la connexion au port 9222 (règle de pare-feu par compte)
 4. Se faire passer pour le navigateur : fermée par le serveur
    le serveur installé refuse un port tenu par un autre compte (debug_endpoint_other_account)
 5. Changer ce que le serveur s'autorise : fermée par le noyau
    le profil de l'opérateur, l'unité du service et le code du serveur ne s'écrivent pas depuis ce compte
 6. Effacer ou réécrire sa trace dans le journal : fermée par le noyau
    le noyau refuse ce compte au dossier du journal, qui est dans le volume
 7. Répondre à la fenêtre de confirmation : ouverte
    l'écran :0 accepte une connexion de ce compte
 8. Lire la mémoire du serveur, du navigateur ou de gocryptfs : fermée par le noyau
    le noyau refuse ce compte à la mémoire des 13 processus essayés de « diwall-mcp »
 9. Capter un mot de passe que l'opérateur tape : ouverte
    ce compte écrit dans ~/.bashrc, que le shell de « alice » lit à chaque ouverture
10. Devenir administrateur : ouverte
    ce compte est du groupe « sudo » : il devient administrateur, avec un mot de passe que la voie 9 capte, ou sans lui si une règle l'en dispense

Niveau atteint : normal

Sacar un archivo del directorio cifrado. cp ejecutado como sudo -u diwall-mcp se rechaza cuando la carpeta de destino es suya, porque diwall-mcp no puede escribir allí. O bien su propia cuenta escribe el archivo, leyéndolo como diwall-mcp y redirigiendo la salida, o bien la copia va a una carpeta donde cualquiera puede escribir, y entonces pertenece a diwall-mcp:

$ mkdir -p /var/tmp/test/recu
$ sudo -n -u diwall-mcp sh -c 'mkdir -p /var/lib/diwall-mcp/Main/downloads && echo "contenu d essai" > /var/lib/diwall-mcp/Main/downloads/essai.txt'
$ sudo -u diwall-mcp cp /var/lib/diwall-mcp/Main/downloads/essai.txt /var/tmp/test/recu/
cp: cannot create regular file '/var/tmp/test/recu/essai.txt': Permission denied
$ sudo -u diwall-mcp cat /var/lib/diwall-mcp/Main/downloads/essai.txt
$ ls -l /var/tmp/test/recu/
total 4
-rw-rw-r-- 1 alice alice 16 Nov  1 00:49 essai.txt
$ cat /var/tmp/test/recu/essai.txt
contenu d essai
$ rm /var/tmp/test/recu/essai.txt
$ chmod 1777 /var/tmp/test/recu
$ sudo -u diwall-mcp cp /var/lib/diwall-mcp/Main/downloads/essai.txt /var/tmp/test/recu/
$ ls -l /var/tmp/test/recu/
total 4
-rw-rw-r-- 1 diwall-mcp diwall-mcp 16 Nov  1 00:49 essai.txt

En una sesión Wayland (GNOME)

Los comandos de arriba se ejecutaron en X11 y luego otra vez en una sesión GNOME en Wayland (Debian 13, GNOME Shell 48.7), donde se probaron las mismas diez vías. Las salidas de esta sección vienen de ese segundo equipo.

La sesión. Pregunte a su sesión cuál es y dónde está XWayland:

$ systemctl --user show-environment
$ grep -E '^(DISPLAY|WAYLAND_DISPLAY|XDG_SESSION_TYPE)='
DISPLAY=:1
WAYLAND_DISPLAY=wayland-0
XDG_SESSION_TYPE=wayland
$ ls -ld /run/user/1000 /run/user/1000/wayland-0
drwx------ 15 alice alice 580 Nov  1 00:15 /run/user/1000
srwxrwxr-x  1 alice alice   0 Nov  1 00:14 /run/user/1000/wayland-0
$ ls -l /tmp/.X11-unix
total 0
srwxrwxrwx 1 root root 0 Nov  1 00:08 X0
srwxrwxr-x 1 alice  alice  0 Nov  1 00:14 X1
srwxrwxr-x 1 alice  alice  0 Nov  1 00:14 X2
$ gnome-shell --version
GNOME Shell 48.7

El directorio de su sesión está cerrado a las demás cuentas (drwx------) y el socket Wayland está dentro: una aplicación de otra cuenta no lo alcanza. Alcanza su pantalla solo por XWayland, que xhost abre.

Lo que cambia xhost. Los comandos son los mismos; el acceso pasa por XWayland. Una ventana de diwall-mcp abierta con el DISPLAY de XWayland existe para su pantalla; con el solo WAYLAND_DISPLAY no se abre en absoluto:

$ sleep 3
$ sudo -n -u diwall-mcp env DISPLAY=:1 zenity --info --title essai-b-x11 --text 'essai b' --timeout 8
MESA: error: Failed to attach to x11 shm
MESA: error: Failed to attach to x11 shm
$ xdotool search --name essai-b-x11
33554436
$ ps -o user=,comm= -p 15904
diwall-+ zenity
$ wait
$ sudo -n -u diwall-mcp ls /run/user/1000/wayland-0
ls: cannot access '/run/user/1000/wayland-0': Permission denied
$ sudo -n -u diwall-mcp env -u DISPLAY -u XAUTHORITY WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/user/1000 GDK_BACKEND=wayland zenity --info --text 'essai b' --timeout 8
(zenity:16088): Gtk-WARNING **: 00:49:10.708: Failed to open display

De estas pruebas salieron dos detalles. El dibujo por defecto de zenity (GTK 4) bajo otra cuenta crea la ventana pero la deja invisible (MESA: error: Failed to attach to x11 shm); desde la versión 0.0.2 el servidor inicia zenity con GSK_RENDERER=cairo y prefiere kdialog cuando está instalado. Y sudo conserva el DISPLAY y el XAUTHORITY de su cuenta salvo que se indique lo contrario: quítelos para probar Wayland solo, como arriba.

Vía 7. En el nivel normal su cuenta responde a la ventana de confirmación de diwall-mcp: la ventana se abre bajo diwall-mcp como la abre el servidor, luego se le da el foco y se responde con xdotool desde su cuenta, y el programa recibe grant.

$ sleep 3
$ sudo -n -u diwall-mcp env DISPLAY=:1 kdialog --title essai-reponse --radiolist 'Autoriser ?' refuse Refuser on grant Autoriser off
Detected locale "C" with character encoding "ANSI_X3.4-1968", which is not UTF-8.
Qt depends on a UTF-8 locale, and has switched to "C.UTF-8" instead.
If this causes problems, reconfigure your locale. See the locale(1) manual
for more information.
$ xdotool search --name essai-reponse
16777252
33554439
$ xdotool windowfocus 33554439
$ xdotool key Down
$ xdotool key Return
$ wait
$ cat /var/tmp/test/reponse.txt
grant
$ ls -l /dev/uinput
crw------- 1 root root 10, 223 Nov  1 00:47 /dev/uinput

En el nivel intransigente, agent no alcanza ni el socket Wayland ni el archivo de socket de XWayland (Permission denied), y no puede usar xdotool ni /dev/uinput. El socket abstracto de XWayland acepta la conexión, así que es la autorización de XWayland la que rechaza a agent: sin cookie legible y sin regla xhost, no pasa nada. Una regla abierta a agent abre la pantalla, y el informe lo dice:

$ sudo -iu agent xdotool getmouselocation
Authorization required, but no authorization protocol specified
Error: Can't open display: (null)
Failed creating new xdo instance
$ sudo -iu agent test -w /dev/uinput
$ sudo -iu agent head -c 1 /dev/input/event0
head: cannot open '/dev/input/event0' for reading: Permission denied
$ sudo -iu agent test -w ~/.bashrc
$ xhost +SI:localuser:agent
localuser:agent being added to access control list
$ sudo -iu agent mcp-server-diwall-browser-setup isolation
Essai des dix voies depuis le compte « agent » (uid 1002) ; le serveur tourne sous « diwall-mcp » (uid 1001).
Rien n'est écrit, aucun mot de passe n'est demandé, aucun sudo n'est lancé, aucun contenu du serveur n'est lu.
 1. Lire le répertoire chiffré : fermée par le noyau
    le noyau refuse ce compte au point de montage (/var/lib/diwall-mcp/Main) : le montage n'a pas d'accès pour un autre compte
 2. Lire le profil du navigateur : fermée par le noyau
    le noyau refuse ce compte au dossier du profil, qui est dans le volume
 3. Piloter le navigateur par son port de débogage : fermée par le noyau
    le noyau écarte la connexion au port 9222 (règle de pare-feu par compte)
 4. Se faire passer pour le navigateur : fermée par le serveur
    le serveur installé refuse un port tenu par un autre compte (debug_endpoint_other_account)
 5. Changer ce que le serveur s'autorise : fermée par le noyau
    le profil de l'opérateur, l'unité du service et le code du serveur ne s'écrivent pas depuis ce compte
 6. Effacer ou réécrire sa trace dans le journal : fermée par le noyau
    le noyau refuse ce compte au dossier du journal, qui est dans le volume
 7. Répondre à la fenêtre de confirmation : ouverte
    l'écran :1 accepte une connexion de ce compte par son socket abstrait
 8. Lire la mémoire du serveur, du navigateur ou de gocryptfs : fermée par le noyau
    le noyau refuse ce compte à la mémoire des 27 processus essayés de « diwall-mcp »
 9. Capter un mot de passe que l'opérateur tape : fermée par le noyau
    les fichiers de démarrage de « alice » et les événements du clavier sont fermés à ce compte
10. Devenir administrateur : fermée par le noyau
    aucun groupe d'administration, aucune règle lisible à son nom, injection dans le terminal refusée ; une règle que seul root lit n'est pas visible d'ici
Niveau atteint : normal
$ sudo -iu agent xdotool getmouselocation
x:1010 y:368 screen:0 window:4194313
$ xhost -SI:localuser:agent
localuser:agent being removed from access control list

Vías 9 y 10. Las mismas pruebas que en X11 dan los mismos resultados. Su cuenta escribe en sus archivos de arranque y no lee los eventos del teclado; use_pty está presente, legacy_tiocsti vale 0, y su regla de sudo hace que la sonda escriba su línea:

$ ls -l /dev/input/event0
crw-rw---- 1 root input 13, 64 Nov  1 00:47 /dev/input/event0
$ head -c 1 /dev/input/event0
head: cannot open '/dev/input/event0' for reading: Permission denied
$ test -w ~/.bashrc
$ echo writable
writable
$ sudo -n grep -rn use_pty /etc/sudoers /etc/sudoers.d/
/etc/sudoers:15:Defaults	use_pty
/etc/sudoers.d/kdesu-sudoers:4:Defaults!/usr/lib/*/libexec/kf5/kdesu_stub !use_pty
$ cat /proc/sys/dev/tty/legacy_tiocsti
0
$ sudo -n true
$ echo 'sudo without a password: yes'
sudo without a password: yes
$ sudo -n -u diwall-mcp sudo -n true
sudo: a password is required

Desde agent, el terminal es otro distinto del suyo, lo que da use_pty, y sudo pide una contraseña:

$ sudo -iu agent tty
/dev/pts/1
$ tty
/dev/pts/0
$ sudo -iu agent sudo -n true
sudo: a password is required

Nivel intransigente: el modelo en una tercera cuenta

Lo que cierra: cada una de las diez vías, por el núcleo salvo la vía 4, que cierra el servidor. Lo que deja abierto: nada. Coste: la cuenta agent; el cliente se inicia con sudo -iu agent, desde su terminal, y use_pty de sudo impide que el cliente inyecte pulsaciones en ese terminal. Debian 13 trae Defaults use_pty en /etc/sudoers, y los dos equipos medidos lo tenían; en otro sistema, compruebe que esa línea está presente, o la inyección no se rechaza.

Paso 1. Cree la cuenta del modelo, del mismo modo que diwall-mcp.

sudo adduser --disabled-password --gecos "" agent
sudo gpasswd -d agent users
id agent
usermod: no changes
Removing user agent from group users
uid=1001(agent) gid=1001(agent) groups=1001(agent)

Paso 2. Entregue el socket al grupo de agent. Un archivo complementario añade el cambio, de modo que deshacerlo quita un solo archivo y deja la unidad del nivel normal como estaba.

sudo install -d /etc/systemd/system/mcp-server-diwall-browser.socket.d
printf '[Socket]\nSocketGroup=agent\n' | sudo tee /etc/systemd/system/mcp-server-diwall-browser.socket.d/uncompromising.conf
sudo systemctl daemon-reload
sudo systemctl restart mcp-server-diwall-browser.socket
stat -c '%A %U %G %n' /run/mcp-server-diwall-browser/mcp.sock
[Socket]
SocketGroup=agent
srw-rw---- root agent /run/mcp-server-diwall-browser/mcp.sock

Paso 3. Su propia cuenta ya no abre el puente; agent sí.

socat - UNIX-CONNECT:/run/mcp-server-diwall-browser/mcp.sock < /dev/null 2>&1 | sed 's/^.*socat\[[0-9]*\] //'
{ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"status","arguments":{}}}'; sleep 6; } | sudo -u agent socat - UNIX-CONNECT:/run/mcp-server-diwall-browser/mcp.sock | tail -n 1 | grep -o 'encrypted_directory[^}]*}\|browser\\": {[^}]*}'
E connect(, AF=1 "/run/mcp-server-diwall-browser/mcp.sock", 41): Permission denied
encrypted_directory\": {\"state\": \"mounted\"}
browser\": {\"attached\": true, \"product\": \"Chrome\", \"version\": \"156.0.8078.73\"}

Paso 4. Declare el puente como comando de su cliente MCP, que funciona bajo agent. En la declaración de la guía del operador, sección 2.1, el command es la línea de abajo y no hay bloque environment: el perfil, la pantalla y el directorio de trabajo los fija la unidad.

{
  "command": ["socat", "STDIO", "UNIX-CONNECT:/run/mcp-server-diwall-browser/mcp.sock"]
}

Paso 5. Pruebe las mismas tres vías desde agent y luego lea el informe desde agent.

sudo -iu agent bash -c 'exec 3<>/dev/tcp/127.0.0.1/9222'
sudo -iu agent ls /var/lib/diwall-mcp/Main
sudo -iu agent sudo -n true
sudo -iu agent mcp-server-diwall-browser-setup isolation
bash: connect: No route to host
bash: line 1: /dev/tcp/127.0.0.1/9222: No route to host
ls: cannot access '/var/lib/diwall-mcp/Main': Permission denied
sudo: a password is required
Essai des dix voies depuis le compte « agent » (uid 1001) ; le serveur tourne sous « diwall-mcp » (uid 1000).
Rien n'est écrit, aucun mot de passe n'est demandé, aucun sudo n'est lancé, aucun contenu du serveur n'est lu.

 1. Lire le répertoire chiffré : fermée par le noyau
    le noyau refuse ce compte au point de montage (/var/lib/diwall-mcp/Main) : le montage n'a pas d'accès pour un autre compte
 2. Lire le profil du navigateur : fermée par le noyau
    le noyau refuse ce compte au dossier du profil, qui est dans le volume
 3. Piloter le navigateur par son port de débogage : fermée par le noyau
    le noyau écarte la connexion au port 9222 (règle de pare-feu par compte)
 4. Se faire passer pour le navigateur : fermée par le serveur
    le serveur installé refuse un port tenu par un autre compte (debug_endpoint_other_account)
 5. Changer ce que le serveur s'autorise : fermée par le noyau
    le profil de l'opérateur, l'unité du service et le code du serveur ne s'écrivent pas depuis ce compte
 6. Effacer ou réécrire sa trace dans le journal : fermée par le noyau
    le noyau refuse ce compte au dossier du journal, qui est dans le volume
 7. Répondre à la fenêtre de confirmation : fermée par le noyau
    l'écran refuse ce compte (sans cookie lisible), et /dev/uinput lui est fermé (1 écran(s) essayé(s))
 8. Lire la mémoire du serveur, du navigateur ou de gocryptfs : fermée par le noyau
    le noyau refuse ce compte à la mémoire des 13 processus essayés de « diwall-mcp »
 9. Capter un mot de passe que l'opérateur tape : fermée par le noyau
    les fichiers de démarrage de « alice » et les événements du clavier sont fermés à ce compte
10. Devenir administrateur : fermée par le noyau
    aucun groupe d'administration, aucune règle lisible à son nom, injection dans le terminal refusée ; une règle que seul root lit n'est pas visible d'ici

Niveau atteint : intransigeant

Volver a un nivel menos estricto

Deshaga todo en orden inverso. Los comandos quitan las cuentas y las unidades; el directorio cifrado de diwall-mcp guarda sus sesiones de navegador, y el último comando del segundo paso lo elimina con ellas: copie antes lo que necesite.

De intransigente a normal. Quite el archivo complementario y luego la cuenta del modelo con su directorio personal. Su propia cuenta vuelve a abrir el puente.

sudo rm /etc/systemd/system/mcp-server-diwall-browser.socket.d/uncompromising.conf
sudo rmdir /etc/systemd/system/mcp-server-diwall-browser.socket.d
sudo systemctl daemon-reload
sudo systemctl restart mcp-server-diwall-browser.socket
sudo deluser --remove-home agent

De normal a imprudente. Retire el acceso a su pantalla, cierre el volumen y el navegador de diwall-mcp, quite el puente, la regla del cortafuegos y la cuenta, y luego el directorio cifrado.

xhost -SI:localuser:diwall-mcp
sudo -iu diwall-mcp mcp-server-diwall-browser-setup close
sudo systemctl disable --now mcp-server-diwall-browser.socket
sudo rm /etc/systemd/system/mcp-server-diwall-browser.socket /etc/systemd/system/mcp-server-diwall-browser@.service
sudo systemctl daemon-reload
sudo rm /etc/nftables.d/diwall-mcp.nft
sudo rmdir /etc/nftables.d
sudo sed -i '\|^include "/etc/nftables.d/diwall-mcp.nft"$|d' /etc/nftables.conf
sudo systemctl reload nftables
sudo deluser --remove-home diwall-mcp
sudo rm -r /var/lib/diwall-mcp
localuser:diwall-mcp being removed from access control list
Fermeture du navigateur avant le démontage.
Volume fermé : /var/lib/diwall-mcp/Main.
Removed '/etc/systemd/system/sockets.target.wants/mcp-server-diwall-browser.socket'.

Cuando una ventana de confirmación ha funcionado bajo diwall-mcp, el último comando puede fallar con userdel: user diwall-mcp is currently used by process …: la ventana dejó un bus de sesión. Detenga los procesos de la cuenta, espere unos segundos, vuelva a suprimir la cuenta y luego quite lo que queda: el archivo de socket en /run (la unidad ya no está, el archivo no se retira con ella) y, en un equipo donde nftables.service está desactivado, la tabla cargada a mano, que reload no descarga:

$ ps -u diwall-mcp -o pid,comm
    PID COMMAND
  15910 dbus-launch
  15911 dbus-daemon
  15949 xdg-desktop-por
  15955 xdg-permission-
  15961 xdg-document-po
  15972 xdg-desktop-por
  15977 gvfsd
  15983 gvfsd-fuse
  15999 at-spi-bus-laun
  16005 dbus-daemon
  16011 at-spi2-registr
$ sudo pkill -u diwall-mcp
$ sleep 5
$ ps -u diwall-mcp -o pid,comm
    PID COMMAND
$ sudo deluser --remove-home diwall-mcp
$ ls -la /run/mcp-server-diwall-browser
total 0
drwxr-xr-x  2 root root  60 Nov  1 00:49 .
drwxr-xr-x 40 root root 960 Nov  1 00:49 ..
srw-rw----  1 root alice    0 Nov  1 00:49 mcp.sock
$ sudo nft list ruleset
table inet diwall_mcp {
	chain output {
		type filter hook output priority filter; policy accept;
		oifname "lo" tcp dport 9222 meta skuid != 1001 reject with icmpx admin-prohibited
	}
}
$ sudo nft delete table inet diwall_mcp
$ sudo rm -r /run/mcp-server-diwall-browser

De imprudente a nada. Cierre su volumen y quite el paquete. Su directorio cifrado queda donde lo puso create; elimínelo usted mismo si no lo necesita.

mcp-server-diwall-browser-setup close
sudo apt purge mcp-server-diwall-browser
Le volume est déjà fermé.
REMOVING:
  mcp-server-diwall-browser*
Summary:
  Upgrading: 0, Installing: 0, Removing: 1, Not Upgrading: 0
  Freed space: 755 kB
Continue? [Y/n] y
Removing mcp-server-diwall-browser (0.0.2-1) ...
mcp-server-diwall-browser removed. Your operator profile and your encrypted directory were not touched.
Purging configuration files for mcp-server-diwall-browser (0.0.2-1) ...
mcp-server-diwall-browser removed. Your operator profile and your encrypted directory were not touched.

Lo que ningún nivel promete

  • Un fallo del núcleo o del servidor.
  • Un secreto que usted pega en una conversación.
  • El uso de una sesión abierta en el navegador dedicado: el modelo puede actuar en ella, dentro de los límites de la lista roja, en todos los niveles.
  • Lo que el proveedor del modelo recibe de las páginas que el modelo lee. Un modelo local elimina esa exposición; no elimina una inyección.

Un nivel se mide en un momento dado: un grupo añadido a una cuenta, una regla de sudoers o un cambio de xhost lo rebajan. Vuelva a ejecutar mcp-server-diwall-browser-setup isolation tras cualquier cambio del equipo.