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
foxcage — Ejecuta Firefox en un contenedor Podman sin root, con capacidades retiradas, red aislada y almacenamiento efímero para contener fugas del sandbox y evitar el compromiso del host. | Kitploit
Herramientas/GitLabGitLab/grepular/foxcage
Herramientas DefensivasSeguridad de ContenedoresVirtualización de SeguridadPrivacidad
GitLabgrepular/foxcage

foxcage

Ejecuta Firefox en un contenedor Podman sin root, con capacidades retiradas, red aislada y almacenamiento efímero para contener fugas del sandbox y evitar el compromiso del host.

Ver Repositorio
16hace 14 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

icono de foxcage foxcage

Ejecuta Firefox en un contenedor Podman sin root para aislamiento de seguridad. Tu navegador se ejecuta con casi ninguna capacidad de Linux, en su propio espacio de usuario y de red, aislado del host — mientras sigue teniendo aceleración GPU completa, audio y soporte DRM.

¿Por qué foxcage?

Firefox ya tiene un sandbox multiproceso que aísla los renderizadores de contenido web usando namespaces de Linux y seccomp-bpf. Para la mayoría de las amenazas, esto es efectivo. foxcage añade una segunda pared: si un atacante explota una vulnerabilidad que escapa del sandbox de Firefox (lo cual ocurre — hay CVEs para esto), aterriza dentro de un contenedor bloqueado en lugar de en tu sesión de usuario completa.

Contra qué protege foxcage

  • Acceso a archivos post-explotación. Una fuga del sandbox en Firefox sin contenedor da acceso a todo lo que tu usuario puede leer: ~/.ssh, ~/.gnupg, perfiles de navegador de otros navegadores, bases de datos de gestores de contraseñas, documentos, código fuente. En foxcage, el atacante solo ve lo que has montado explícitamente.
  • Residuos de rastreo en disco. La jaula efímera @tmp deja cero rastro en disco después de cerrar la ventana — incluyendo extensiones, estado HSTS, caché de sesión TLS y caché DNS que la Navegación Privada de Firefox aún persiste. Múltiples jaulas @tmp se ejecutan de forma concurrente sin interferir entre sí.
  • Persistencia. En Firefox sin contenedor, el malware puede escribir en ~/.config/autostart, ~/.bashrc, cron, o en cualquier otro lugar para sobrevivir a un reinicio. El contenedor efímero de foxcage (--rm) significa que nada persiste a menos que lo hayas montado con bind.
  • Movimiento lateral en la red. Por defecto, el contenedor no puede sondear servicios en localhost. En Firefox sin contenedor, una fuga del sandbox tiene acceso completo a la red. (Usa [network] mode = "host" si una jaula necesita acceso a localhost, p. ej. para desarrollo local — pero consulta la advertencia en "Redes": el modo host también expone los sockets Unix abstractos del host).
  • Escalada de privilegios. El contenedor elimina todas las capacidades de Linux excepto CAP_SYS_CHROOT y bloquea la adquisición de nuevos privilegios. Los binarios setuid, los exploits del kernel mediante syscalls oscuras y rutas de escalada similares quedan cortados.

Contra qué no protege foxcage

  • Ataques a nivel de navegador. El phishing, las extensiones maliciosas y cualquier cosa que opere dentro de la funcionalidad normal de Firefox no se ve afectada — foxcage aísla el contenedor del host, no al usuario del navegador.
  • Directorios montados con bind. Cualquier cosa que montes (profile, downloads_dir, montajes bind adicionales) es totalmente accesible para un navegador comprometido. Si montas un directorio de perfil del host, un atacante puede manipularlo igual que en Firefox sin contenedor.
  • Captura de audio vía PulseAudio. El socket de PulseAudio se monta con bind dentro del contenedor. Aunque está montado de solo lectura a nivel del sistema de archivos, los sockets de dominio Unix son bidireccionales — un proceso comprometido aún puede enviar solicitudes de grabación a través del socket. Una fuga del sandbox del navegador podría potencialmente grabar audio del micrófono del host.
  • Exploits del compositor Wayland. El socket de Wayland se pasa a través. Los compositores Wayland aíslan a los clientes entre sí por diseño, pero una vulnerabilidad en el propio compositor sería alcanzable.

Configuración de seguridad

El contenedor se ejecuta con:

  • Todas las capacidades de Linux eliminadas (solo se añade CAP_SYS_CHROOT para el sandbox de contenido de Firefox; CAP_SETUID/CAP_SETGID se añaden temporalmente cuando init.root está configurado)
  • no-new-privileges para prevenir la escalada de privilegios
  • Namespace de usuario sin root (--userns keep-id)
  • /dev/shm privado (no compartido con el host) — tamaño configurable vía shm_size
  • Red aislada mediante pasta con loopback del host bloqueado por defecto
  • DNS usa el DNS del host por defecto (configurable vía network.dns)
  • Solo sockets específicos de XDG_RUNTIME_DIR se montan con bind (Wayland, PulseAudio, PipeWire y el proxy D-Bus filtrado) — el directorio de runtime completo del host nunca se expone
  • El acceso al bus de sesión D-Bus del host siempre está mediado por un xdg-dbus-proxy filtrado que se ejecuta en el host. Solo , , y (para forks) el propio namespace del fork (p. ej. ) son alcanzables — los servicios de sesión como el llavero y el agente SSH/GPG están bloqueados

Cada opción de [network] y [mounts] que habilites intercambia algo de aislamiento por conveniencia. Los valores por defecto son la configuración más restrictiva que aún te da un navegador utilizable.

Requisitos

  • Python 3.11+
  • Podman (sin root)
  • Compositor Wayland (X11 no es compatible)
  • pasta (sudo apt install passt) — a menos que network.mode = "host"
  • xdg-dbus-proxy (sudo apt install xdg-dbus-proxy)
  • PulseAudio o PipeWire con compatibilidad con PulseAudio (para audio)
  • GPU con soporte DRI — opcional; sin /dev/dri foxcage advierte y Firefox renderiza en software. Los controladores VA-API para Intel, AMD y nouveau están instalados en la imagen, así que la decodificación de video por hardware funciona sin paquetes de controladores del host — consulta Decodificación de video por hardware (VA-API)

Ejecuta foxcage como tu usuario de escritorio normal, no como root ni vía sudo — el sandbox mapea tu usuario dentro del contenedor, y ejecutarlo como root elimina el aislamiento para el que existe foxcage. Se niega a iniciarse como root.

Entorno probado: Debian 13 (Trixie) con GNOME 3. Otras distribuciones de Linux y compositores Wayland pueden funcionar pero no han sido probados.

Instalación

foxcage es un único script de Python sin dependencias fuera de la biblioteca estándar de Python. Cópialo a un directorio en tu PATH:```sh sudo cp foxcage /usr/local/bin/foxcage

root@kitploit:~
O para una instalación local del usuario:```sh
cp foxcage ~/.local/bin/foxcage

Asegúrate de que el script sea ejecutable (chmod +x foxcage).

Comprueba qué revisión tienes con foxcage --version — útil al reportar un problema, ya que foxcage se instala copiando un solo archivo.

Uso```sh

./foxcage

root@kitploit:~
En la primera ejecución, el script construye la imagen del contenedor (descarga Firefox desde Mozilla, instala dependencias mínimas de Debian) y luego inicia Firefox. En ejecuciones posteriores, foxcage comprueba si hay actualizaciones de Firefox y reconstruye la imagen automáticamente cuando hay una nueva versión disponible. La imagen también se reconstruye periódicamente (cada 7 días por defecto) para incorporar actualizaciones de paquetes del sistema. Si la comprobación de actualizaciones falla (error de red, tiempo de espera agotado), se registra una advertencia y se utiliza la imagen existente — el arranque nunca se bloquea.

Pasa argumentos a Firefox:```sh
./foxcage https://example.com

Combina una jaula con nombre con las banderas de Firefox:```sh ./foxcage @work --kiosk https://example.com

root@kitploit:~
Si una jaula ya está en ejecución, la URL se abre en una nueva pestaña del navegador existente en lugar de iniciar un segundo contenedor. Ejecutar `foxcage` (o `foxcage @cage`) sin URL contra una jaula en ejecución termina limpiamente con un mensaje de "la jaula ya está en ejecución" — foxcage no puede elevar una ventana Wayland existente desde fuera del contenedor, así que no lo intenta.

Las banderas por lanzamiento **no** se aplican cuando una jaula ya está en ejecución. `--dns`, `--ipv4-only`, `--lifetime`, `--color` y `--fork` se consumen cuando el contenedor arranca, y la configuración de un contenedor en ejecución no se puede cambiar desde fuera, por lo que se ignoran con una advertencia. Cierra la jaula y vuelve a ejecutarla para aplicarlas.

> Usa la clave de configuración `private_browsing` para sesiones en modo privado — *no* la bandera CLI cruda `--private-window` de Firefox. La clave de configuración establece el modo privado a nivel de sesión (`browser.privatebrowsing.autostart`), de modo que las invocaciones posteriores de `foxcage @cage URL` puedan reabrir en pestañas. `--private-window` como paso directo de Firefox haría privada solo la primera ventana y rompería el comportamiento de reabrir en pestaña descrito arriba.
>
> **Aviso:** las sesiones habilitadas mediante `private_browsing = true` no muestran las señales visuales habituales de ventana privada de Firefox (barra de acento púrpura, icono de máscara, "(Navegación privada)" en el título). Esto se debe a que cada ventana de la sesión es privada, por lo que Firefox no tiene ninguna ventana no privada con la que contrastar visualmente — suprime el indicador. La sesión *es* genuinamente privada; verifícalo si quieres visitando `about:privatebrowsing` en la jaula (muestra la página estándar de información de Navegación privada) o `about:config` y comprobando `browser.privatebrowsing.autostart = true`.

### Navegación efímera con `@tmp`

Para enlaces de un solo uso que no deben dejar rastro, usa la jaula reservada `tmp`:```sh
./foxcage @tmp https://somewhere-suspicious.example

Cada lanzamiento con @tmp es un Firefox nuevo y desechable sin perfil persistente. Cuando la ventana se cierra, todo desaparece: cookies, caché, historial, extensiones, estado HSTS, caché de sesión TLS, caché DNS y estado de pestañas guardado. Esto va más allá de la Navegación Privada de Firefox, que aún conserva extensiones y una buena parte del estado en disco.

Varias jaulas @tmp se ejecutan de forma concurrente, cada una aislada de las demás. La barra de menú muestra FoxCage - tmp (<id corto>) para que puedas distinguir las ventanas efímeras simultáneas.

Las jaulas efímeras abren una página en blanco al iniciar y pestañas nuevas en blanco: la página de inicio predeterminada de Firefox y el contenido de pestañas nuevas (sitios principales, recomendaciones de Pocket, flujo de actividad) son puro ruido en un perfil nuevo que está a punto de descartarse, por lo que se suprimen. Las jaulas persistentes mantienen los valores predeterminados de Firefox.

Jaulas efímeras con nombre

Si quieres un nombre significativo en una sesión desechable (por ejemplo, una madriguera de investigación que quieras reabrir en una pestaña nueva), usa @tmp-<nombre>:```sh ./foxcage @tmp-research https://example.com # first call → new window ./foxcage @tmp-research https://another.example # second call → new tab in the existing window

root@kitploit:~
`@tmp-<name>` sigue siendo efímero: cuando cierras la ventana, todo desaparece. La diferencia con el `@tmp` simple es que los segundos lanzamientos con el mismo nombre **reutilizan la ventana existente** (igual que las jaulas persistentes), por lo que puedes añadir más pestañas más tarde sin iniciar una copia paralela. El `@tmp` simple mantiene su comportamiento de "cada lanzamiento es un desechable nuevo".

La etiqueta de la barra de menú muestra el nombre que elegiste (`FoxCage - tmp-research`), de modo que la ventana queda etiquetada de forma significativa.

#### Personalizar los valores predeterminados efímeros

Crea `~/.config/foxcage/tmp.toml` para establecer los valores predeterminados de todas las jaulas efímeras (tanto el `@tmp` simple como cada `@tmp-<name>`). Por ejemplo:```toml
private_browsing = true
lifetime = "30m"
extensions = ["ublock-origin"]

[network]
dns = "cloudflare"

Cada lanzamiento efímero ahora obtiene una ventana privada, uBlock Origin, Cloudflare DoH y se cierra automáticamente después de 30 minutos, con la efimeridad completa intacta. Los efímeros nombrados heredan tmp.toml por defecto; si quieres anularlo por nombre, crea ~/.config/foxcage/tmp-<name>.toml. Ese archivo se aplica entonces en lugar de tmp.toml — sin fusión, el archivo más específico gana directamente. Copia los valores predeterminados compartidos en él si los quieres.

Cualquier cosa que puedas configurar en la configuración de una jaula regular funciona aquí, excepto la clave que anularía la efimeridad en sí:

  • profile — error grave.

Apunta a un directorio de perfil persistente en el host, lo que contradice directamente el propósito de @tmp. Si quieres una jaula aislada con un perfil persistente, usa una jaula nombrada regular (@work, @research, etc.) que no comience con tmp-.

Extensiones preinstaladas

Una jaula puede tener extensiones integradas en su imagen y forzar su instalación en cada lanzamiento:```toml extensions = ["ublock-origin"]

root@kitploit:~
Pon eso en `~/.config/foxcage/tmp.toml` y **cada jaula desechable arranca con uBlock Origin ya en ejecución** — lo cual importa, porque una jaula efímera es, por lo demás, el navegador menos protegido que tienes, usado precisamente en los enlaces en los que menos confías. Un perfil `@tmp` recién creado no tiene extensiones en absoluto, e instalar una a mano no tiene sentido en una sesión que se destruye a sí misma al cerrarse.

Cada entrada puede ser el nombre corto de la URL del add-on en addons.mozilla.org, la propia URL del listado, o el ID del add-on:```toml
extensions = [
    "ublock-origin",
    "https://addons.mozilla.org/firefox/addon/noscript/",
    "[email protected]",
]

Add-ons se resuelven a través de la API de addons.mozilla.org al iniciar, se descargan durante la construcción de la imagen y se verifican contra el SHA-256 que publica AMO. La versión resuelta forma parte del Containerfile, por lo que una nueva versión de una extensión cambia el hash de la imagen y desencadena una reconstrucción: las extensiones se actualizan igual que Firefox, y por la misma razón: nada se instala en tiempo de ejecución, por lo que un perfil efímero nuevo nunca vuelve a descargar nada.

Debido a que se instalan mediante política empresarial y no manualmente:

  • No se pueden eliminar ni deshabilitar desde dentro de la jaula (about:addons las muestra como instaladas por tu organización).
  • Están habilitadas en ventanas privadas, por lo que siguen funcionando en una jaula que ejecuta private_browsing = true. Esto requiere Firefox 136 o ESR 128.8; las versiones anteriores ignoran el ajuste y dejan el add-on inerte en ventanas privadas.
  • Su icono se coloca en la barra de herramientas, para que puedas ver que el bloqueador está realmente ahí.
  • Las actualizaciones de extensiones dentro del navegador están desactivadas. Las actualizaciones llegan con las reconstrucciones de la imagen.

Limitaciones:

  • Solo AMO. Las extensiones deben estar listadas en addons.mozilla.org — esa consulta es la que proporciona el ID de add-on que necesita una entrada de política, además del digest que la construcción verifica. Una URL .xpi simple se rechaza.
  • Sin fijación de versión. Una reconstrucción toma lo que AMO liste actualmente como la última versión del add-on.
  • AMO debe ser accesible para construir. Si la consulta falla y la jaula ya tiene una imagen, foxcage advierte y se inicia con la existente; si la jaula aún no tiene imagen, sale en lugar de construir una jaula que silenciosamente carezca de los add-ons que solicitaste.
  • Todas las jaulas efímeras comparten una imagen. @tmp y cada @tmp-<nombre> construyen una única imagen foxcage-tmp, por lo que dar a una efímera con nombre una lista de extensions diferente a la de tmp.toml hace que ambas se reconstruyan una sobre la otra en lanzamientos alternos. Mantén las listas de extensiones efímeras en tmp.toml.

Sobrescribir DNS por lanzamiento

La bandera --dns (y la clave de configuración equivalente network.dns) acepta tres formas:```sh ./foxcage @tmp --dns 1.1.1.1 https://example.com # IP ./foxcage @tmp --dns cloudflare https://example.com # alias ./foxcage @tmp --dns https://dns.nextdns.io/ # custom DoH URI

root@kitploit:~
**Cuando el valor coincide con un proveedor conocido (por alias o por IP), foxcage habilita automáticamente DNS sobre HTTPS forzado hacia ese proveedor.** El TRR de Firefox se configura en modo 3 (estricto, sin respaldo en texto claro) con la dirección de arranque completada para que no haya fugas de resolución sin cifrar al inicio. Verás un aviso de una línea en stderr como `Enabling DNS over HTTPS via Cloudflare`.

Alias integrados:

| Alias | IP | Filtrado |
|-------|------|-----------|
| `cloudflare` | 1.1.1.1 | ninguno |
| `cloudflare-security` | 1.1.1.2 | bloquea malware |
| `cloudflare-family` | 1.1.1.3 | bloquea malware + contenido adulto |
| `google` | 8.8.8.8 | ninguno |
| `quad9` | 9.9.9.9 | bloquea malware (predeterminado de Quad9) |
| `quad9-unfiltered` | 9.9.9.10 | ninguno |
| `adguard` | 94.140.14.14 | bloquea anuncios + rastreadores |
| `adguard-family` | 94.140.14.15 | anuncios + rastreadores + contenido adulto |
| `opendns` | 208.67.222.222 | algunos |

Una IP que no esté en la tabla (p. ej., el Pi-hole de tu LAN) permanece solo en texto claro — no se habilita DoH, ya que foxcage no conoce el endpoint DoH correspondiente. Usa el formato URI para eso: `--dns https://pi.hole/dns-query` (con un certificado válido) habilita DoH y deja el DNS del contenedor intacto.

El formato URI omite configurar el DNS en texto claro del contenedor, por lo que cualquier cosa dentro del contenedor que no sea Firefox seguirá usando el DNS del host. Esto es deliberado — `--dns URI` significa "haz que Firefox use este resolutor DoH", y punto.

`--dns` es incompatible con `network.mode = "host"`, que ya tiene acceso completo a la red del host.

### Identificación visual de la jaula

Cada jaula con nombre recibe un color de acento en la barra de menú para que puedas distinguir las ventanas de un vistazo. **No necesitas configurar nada** — el color se deriva de forma determinista del nombre de la jaula (hash SHA256 convertido en un tono, con saturación y luminosidad fijas). `@banking`, `@work`, `@personal`, `@tmp-research` obtienen colores distintos y estables sin que muevas un dedo.

La jaula predeterminada (anónima) mantiene el naranja integrado.

Si quieres anular el color derivado automáticamente, configúralo explícitamente:```toml
# ~/.config/foxcage/banking.toml
color = "#dc2626"   # red — overrides the auto-derived colour
root@kitploit:~
## 🛡️ Características

- **Escaneo de puertos**: Detecta puertos abiertos y servicios en ejecución.
- **Detección de vulnerabilidades**: Identifica vulnerabilidades conocidas en los servicios detectados.
- **Fuerza bruta**: Prueba credenciales débiles en servicios como SSH, FTP y HTTP.
- **Generación de informes**: Genera informes detallados en formato HTML y PDF.
- **Interfaz de línea de comandos**: Fácil de usar y automatizable.
- **Soporte multiplataforma**: Funciona en Linux, macOS y Windows.

## 📦 Instalación

Para instalar la herramienta, clona el repositorio y ejecuta el script de instalación:

```bash
git clone https://github.com/example/tool.git
cd tool
./install.sh

🚀 Uso

Una vez instalado, puedes ejecutar la herramienta con el siguiente comando:

root@kitploit:~
tool --target example.com

Opciones disponibles

OpciónDescripción
--targetEspecifica el objetivo a escanear.
--ports

📄 Ejemplo de informe

A continuación se muestra un ejemplo de cómo se ve un informe generado:

root@kitploit:~
<!DOCTYPE html>
<html>
<head>
    <title>Informe de Escaneo</title>
</head>
<body>
    <h1>Resultados del Escaneo</h1>
    <p>Objetivo: example.com</p>
    <ul>
        <li>Puerto 22 (SSH): Abierto</li>
        <li>Puerto 80 (HTTP): Abierto</li>
        <li>Puerto 443 (HTTPS): Abierto</li>
    </ul>
</body>
</html>

🤝 Contribuciones

Las contribuciones son bienvenidas. Por favor, lee el archivo CONTRIBUTING.md para más detalles sobre cómo contribuir al proyecto.

📝 Licencia

Este proyecto está licenciado bajo la Licencia MIT. Consulta el archivo LICENSE para más información.

root@kitploit:~
./foxcage @experiment --color "#10b981" https://example.com   # teal, one-off
```
Acepta CSS hex estándar: `#rgb`, `#rrggbb` o `#rrggbbaa` (con alfa). Los colores derivados automáticamente están ajustados para ser visibles tanto en barras de menú claras como oscuras (luminosidad fijada al 55 %, saturación al 75 %), por lo que no deberías necesitar sobrescribirlos por motivos de tema.

### Jaulas con límite de tiempo

La bandera `--lifetime` (y la clave de configuración equivalente `lifetime`) cierra automáticamente una jaula después de una duración determinada. El formato es `<número><unidad>` con unidad `s`, `m` u `h`:```sh
./foxcage @tmp --lifetime 10m https://example.com
./foxcage @work --lifetime 2h
```
The countdown starts when Firefox actually launches inside the cage — container startup and image-build time don't eat into your budget. The cage's menu-bar label shows the countdown alongside the cage identity — e.g. `FoxCage - tmp (a3f2b1) | 9m` — updated once per minute while there's more than a minute left, and once per second in the final minute. When the countdown hits zero Firefox closes itself and the container exits. If you close Firefox yourself before the lifetime is up, nothing unusual happens.

Set a default lifetime per cage in its config:```toml
# ~/.config/foxcage/tmp.toml — every @tmp launch auto-closes after 15 minutes
lifetime = "15m"
private_browsing = true
```
`--lifetime` en la línea de comandos tiene prioridad sobre cualquier valor de configuración.

Fuerza una reconstrucción completa de la imagen (vuelve a descargar Firefox y todos los paquetes del sistema):```sh
./foxcage --rebuild
```
Un contenedor en ejecución conserva la imagen con la que se inició, incluso después de que foxcage reconstruya la etiqueta de la imagen. Si intentas abrir una pestaña en una jaula cuya imagen se ha actualizado desde entonces (mediante `--rebuild`, una actualización de Firefox o la reconstrucción programada), foxcage se niega con un error (también mostrado como notificación de escritorio) y te pide que cierres Firefox y lo vuelvas a lanzar, lo que inicia un contenedor nuevo con la imagen actual. Con `--rebuild` y una jaula activa, foxcage avisa de antemano, realiza la compilación y luego aplica la misma comprobación.

### Actualizaciones

foxcage comprueba si hay nuevas versiones del navegador en cada lanzamiento: la API de lanzamientos de Mozilla para Firefox y el endpoint de lanzamientos de GitLab para LibreWolf. Si hay una actualización disponible, la imagen del contenedor se reconstruye automáticamente. La imagen también se reconstruye periódicamente (cada 7 días por defecto) para incorporar las actualizaciones de seguridad de Debian. El actualizador automático integrado del navegador está deshabilitado, ya que las actualizaciones se gestionan a nivel de imagen.

Si la comprobación de actualizaciones falla (sin red, tiempo de espera de la API), se imprime una advertencia y se usa la imagen existente; siempre puedes navegar.

La cadencia de actualización se encuentra en el nivel superior de la configuración; el fijado de versión y canal se encuentra en la sección por bifurcación:```toml
rebuild_days = 14      # rebuild for base-image updates every 14 days (0 to disable)

[firefox]
channel = "beta"       # track the beta channel instead of stable (firefox only)
version = "149"        # pin to Firefox 149.x (latest patch release)
```
**Fijar una versión ESR también necesita el canal.** El índice de versiones de Mozilla lista las versiones ESR sin el sufijo `esr` que llevan sus descargas, por lo que un `version = "140"` sin más en el canal predeterminado resuelve a una versión que no existe. Establece ambos:```toml
[firefox]
channel = "esr"
version = "140"        # → 140.13.0esr
```
Un pin que no coincide con ninguna versión se convierte ahora en un error que nombra el pin, en lugar de recurrir silenciosamente a la última versión. Un fallo temporal al alcanzar la API de Mozilla sigue mostrando una advertencia y continúa con la imagen existente, de modo que una red inestable nunca bloquea el arranque.

Los pines con sufijo deben estar completamente calificados: `"140.13.0esr"` y `"150.0b9"` funcionan, mientras que `"140esr"` y `"150b9"` se rechazan al cargar la configuración porque ninguna versión puede coincidir con ellos. Lo mismo se aplica a las revisiones de LibreWolf: `"146.0.1-1"` funciona, `"146-1"` no.

Para forzar una reconstrucción completa inmediata: `./foxcage --rebuild`

### Claves de firma revocadas

foxcage se niega a instalar una compilación del navegador cuya firma fue realizada por una subclave de firma que el proyecto upstream revocó como **comprometida** (razón de revocación RFC 4880 `0x02`). `gpg --verify` no hace esto por sí solo: imprime una advertencia y sale con código 0, por lo que sin la comprobación adicional, una clave de firma filtrada seguiría autenticando una descarga manipulada.

Una negativa se ve así y hace fallar la compilación en lugar de instalar:```
foxcage: REFUSING /tmp/SHA512SUMS - signed by 09BEED63F3462A2DFFAB3B875ECB6497C1A20256,
which its owner revoked as compromised.  This build cannot be trusted; wait for
upstream to re-sign this release with a current key.
```
No hay nada que configurar ni anulación posible. Si te encuentras con esto, la solución viene de upstream: o fijas una versión firmada con una clave actual, o esperas a que la versión afectada se vuelva a firmar.

La rotación rutinaria de claves se trata de forma diferente. Una subclave revocada como reemplazada, retirada o sin motivo indicado no invalida las firmas realizadas *antes* de la revocación, por lo que esas versiones se instalan con una advertencia. Una firma con fecha *posterior* a cualquier revocación se rechaza sea cual sea el motivo indicado.

**Rotación de claves de Mozilla en agosto de 2026.** Mozilla revocó la subclave de firma `09BEED63…C1A20256` el 2026-08-06 después de que una copia sin cifrar se enviara a un repositorio privado de GitHub, y la sustituyó por `827E6586…76767AA3`. Las versiones de Firefox firmadas con la subclave antigua — todo lo comprendido entre el 2025-03-13 y el 2026-08-06, que en el momento de escribir esto aún incluye la ESR actual (`140.13.0esr`) y cualquier fijación de `version` dentro de ese intervalo — son rechazadas por la comprobación anterior. Los canales de lanzamiento y beta no se ven afectados. foxcage obtiene las claves de `keys.openpgp.org` en lugar de `keyserver.ubuntu.com` porque este último no sirvió ni la subclave de reemplazo ni la revocación durante días después de la rotación; un servidor de claves desactualizado rompería las compilaciones por completo y reduciría silenciosamente la comprobación de revocación a una operación nula.

### Forks de Firefox (LibreWolf)

foxcage puede ejecutar un fork de Firefox orientado a la privacidad en lugar del Firefox de upstream:```toml
fork = "librewolf"         # default is "firefox"

[librewolf]
version = "146.0.1-1"      # optional pin; partial pins ("146", "146.0.1") also work
```
O por lanzamiento mediante CLI:```sh
foxcage @tmp --fork librewolf https://example.com
```
**LibreWolf**: bifurcación de Firefox endurecida para la privacidad: protección estricta contra el rastreo, DoH, RFP, telemetría desactivada por defecto. Archivo tar de Linux firmado desde GitLab (`librewolf-community/browser/bsys6`), verificado con GPG contra la clave de los mantenedores de LibreWolf `662E 3CDD 6FE3 2900 2D0C A5BB 4033 9DD8 2B12 EF16` con una verificación cruzada de `.sha256sum` adjunta, bajo las mismas [reglas de revocación](#revoked-signing-keys) que Firefox. El `librewolf.cfg` incluido de LibreWolf se conserva; foxcage añade sus propias preferencias encima en lugar de sobrescribirlo. Los mantenedores rotaron su subclave de firma el 2026-04-25 sin indicar un motivo; los archivos tar actuales se firmaron antes de esa fecha, por lo que se instalan con una advertencia en lugar de ser rechazados.

**El canal es solo para Firefox**: `firefox.channel = "beta" | "esr"` se rechaza cuando `fork` es cualquier valor distinto de `"firefox"`. LibreWolf tiene una única vía de lanzamiento.

Cambiar `fork` (mediante configuración o `--fork`) cambia el hash del Containerfile, lo que desencadena una reconstrucción en el siguiente lanzamiento: no se necesita `--rebuild` manual.

#### Compatibilidad de perfiles

> **Usa un perfil dedicado por fork.** La opción más segura por defecto es dejar que foxcage aprovisione su propio perfil (omite `profile` en la configuración), o apuntar `profile` a un directorio que no abras también desde el host.

- **LibreWolf**: *normalmente* es seguro compartirlo con tu perfil de Firefox del host: LibreWolf sigue las versiones de Firefox en unos pocos días, por lo que los conflictos de esquema de `compatibility.ini` son raros. Riesgos: (1) solo es seguro el uso secuencial (el archivo de bloqueo de Firefox impide aperturas simultáneas); (2) en la breve ventana posterior a un lanzamiento estable de Firefox, ejecutar primero Firefox y luego LibreWolf puede activar un diálogo de migración de "usado por una versión más reciente"; (3) las funciones que LibreWolf elimina (Sync, Pocket, cuenta de Mozilla) simplemente no funcionan, pero no corrompen datos.

### Jaulas con nombre

Ejecuta instancias sandbox separadas con su propia configuración y perfil de Firefox:```sh
./foxcage @work
```
Esto carga `~/.config/foxcage/work.toml` y utiliza una imagen separada (`foxcage-work`), un contenedor (`foxcage-work`) y un volumen (`foxcage-work-profile`). El archivo de configuración debe existir para las jaulas con nombre. Los nombres de las jaulas solo pueden contener letras, dígitos, guiones y guiones bajos.

## Configuración

Los archivos de configuración se encuentran en `$XDG_CONFIG_HOME/foxcage/` (por defecto en `~/.config/foxcage/`).

- `config.toml` — jaula predeterminada (opcional, con valores predeterminados sensatos sin él)
- `<name>.toml` — jaula con nombre, cargada con `@<name>` (obligatorio)

Las claves de configuración desconocidas se rechazan con un error. Consulta `config.toml.example` para ver todas las opciones disponibles con sus valores predeterminados.

### Ejemplo de config.toml```toml
# Bind-mount a host Firefox profile directory into the cage
profile       = "~/.mozilla/firefox/xxxxxxxx.default-release"

# Allow downloading files to ~/Downloads
downloads_dir = "~/Downloads"

# Extensions pre-installed into the cage (addons.mozilla.org short name,
# listing URL, or add-on ID). Most useful in tmp.toml.
# extensions = ["ublock-origin"]

# Shared memory size for Firefox IPC (default: 256m)
# shm_size = "256m"

# Pass through webcam devices (/dev/video*)
# webcam = true

# Pass through host CUPS socket for locally-connected printers (e.g. USB)
# local_printers = true

# Pass through FIDO2/U2F security key devices (/dev/hidraw*)
# security_keys = true

# Always open Firefox in private browsing mode
# private_browsing = true

# Auto-close the cage after a duration (<int> with unit s, m, or h)
# lifetime = "30m"

# Accent colour for the menu-bar label.  Named cages get a colour derived
# from the name automatically; set this to override it.
# color = "#4a90e2"

# Browser fork: "firefox" (default) or "librewolf"
# fork = "librewolf"

# Full image rebuild interval in days for base-image updates (default: 7, 0 to disable)
# rebuild_days = 7

[firefox]
# Firefox release channel: "release" (default), "beta", "esr".
# Only valid when fork = "firefox".
# channel = "release"

# Pin to a specific Firefox version (overrides channel).
# Partial versions like "149" or "149.0" resolve to the latest patch release.
# Suffixed versions must be fully qualified ("140.13.0esr", "150.0b9"); to
# follow the ESR line by major version, pair a numeric pin with
# channel = "esr" above.
# version = "149.0.2"

[librewolf]
# Pin to a specific LibreWolf version. Tags are "<firefox-version>-<rev>",
# e.g. "146.0.1-1". Partial pins like "146" or "146.0.1" also work.
# version = "146.0.1-1"

[network]
# "host" for full host networking (needed if the cage has to reach services
# on the host's localhost), or omit for isolated pasta (default)
# mode = "host"

# DNS server (isolated mode only, default: host DNS)
# dns = "1.1.1.1"

# Disable IPv6 in the cage (isolated mode only)
# ipv4_only = true

[mounts]
# Additional bind mounts into the container. Supported forms:
#   "~/Documents"                     — same path in container
#   "~/Documents:~/Documents"         — ~ expanded on both sides
#   "~/Documents:/home/user/Documents" — explicit container path
# Append :ro for read-only, e.g. "~/Documents:ro"
# nosuid,noexec are always enforced on bind mounts; an explicit "exec" or
# "suid" is rejected rather than silently dropped.
# Host paths must be absolute or start with "~/".
bind = [
    "~/Documents:ro",
]

[init]
# Commands to run at image build time (as root). Changes trigger a rebuild.
# build = ["apt-get update && apt-get install -y --no-install-recommends vim"]

# Commands to run at container startup as root, before Firefox.
# root = ["chown user:user /some/path"]

# Commands to run at container startup as your user, before Firefox.
# user = ["mkdir -p ~/custom-dir"]
```
### Perfil de Firefox del host

Para compartir un perfil de Firefox del host con la jaula, establece `profile` en el directorio del perfil. Encuentra la ruta de tu perfil visitando `about:profiles` en Firefox en el host — o simplemente apunta a un directorio vacío nuevo si quieres que la jaula comience con un perfil limpio que persista en el host.```toml
profile = "~/.mozilla/firefox/xxxxxxxx.default-release"
```
Solo este directorio se monta en la jaula. Los perfiles hermanos bajo `~/.mozilla/firefox/` y el registro `profiles.ini` no están expuestos: una jaula comprometida no puede manipularlos.

Si `profile` no está definido, un volumen de Podman con nombre almacena el perfil de Firefox en su lugar (consulta "Qué persiste" más abajo). Si el mismo perfil ya está abierto en Firefox en el host, el archivo de bloqueo por perfil de Firefox provocará un conflicto: usa un perfil dedicado por jaula.

### Redes

De forma predeterminada, el contenedor usa pasta con el loopback del host bloqueado y el DNS del host. pasta requiere podman 4.4 o más reciente (ha sido el valor predeterminado sin root desde podman 5.0).

**Red de host** elimina el aislamiento de red por completo. Úsala cuando la jaula necesite acceder a servicios en el `localhost` del host (por ejemplo, un servidor de desarrollo local, una base de datos en `127.0.0.1`):```toml
[network]
mode = "host"
```
`dns` no se puede combinar con `mode = "host"` — la red de host ya utiliza el resolver del host.

> **El modo host cede más que localhost.** Coloca la jaula en el namespace de red del host, y los sockets Unix abstractos están limitados a ese namespace en lugar de al sistema de archivos. Así, una jaula en modo host puede alcanzar directamente los sockets de dirección abstracta del host — incluido `@/tmp/.X11-unix/X0` de Xwayland si ejecutas X11 o Xwayland (registro de entrada, a pesar de que foxcage es solo Wayland), y un bus de sesión configurado con `unix:abstract=…`, lo que eludiría el proxy D-Bus filtrado. Esto es inherente a compartir la pila de red, no algo que foxcage pueda filtrar. Usa el modo host cuando lo necesites, y prefiere una jaula con nombre que solo lances para ese propósito.

**Jaulas solo IPv4** deshabilitan IPv6 por completo:```toml
[network]
ipv4_only = true
```
O bien al lanzarlo con la bandera `--ipv4-only` (forma corta `-4`, como en `ssh`/`curl`/pasta):```sh
./foxcage @tmp -4 https://example.com
```
Esto ejecuta pasta en modo solo IPv4 (`-4`), por lo que el contenedor no tiene ninguna pila IPv6, y además establece `network.dns.disableIPv6` en Firefox para que no resuelva registros AAAA — lo cual importa cuando DoH está habilitado, ya que las respuestas de DoH omiten el resolutor del contenedor. `ipv4_only` no se puede combinar con `mode = "host"` — la red de host utiliza directamente la pila de red del host, así que deshabilita IPv6 en el host en su lugar.

### Comandos de init

Ejecuta comandos personalizados en el momento de la compilación o al iniciar el contenedor mediante `[init]`:

- **`build`** — se ejecuta en el momento de la compilación de la imagen como root. Úsalo para instalar paquetes u otra configuración lenta. Los cambios en los comandos de compilación activan automáticamente una reconstrucción de la imagen.
- **`root`** — se ejecuta al iniciar el contenedor como root, antes de Firefox. Úsalo para tareas rápidas de root en tiempo de ejecución (ajustar permisos, escribir archivos de configuración).
- **`user`** — se ejecuta al iniciar el contenedor como tu usuario, antes de Firefox. Úsalo para crear directorios, configurar el estado a nivel de usuario.```toml
[init]
build = [
    "apt-get update && apt-get install -y --no-install-recommends fonts-noto-cjk",
    "rm -rf /var/lib/apt/lists/*",
]
root = ["chmod 777 /tmp/shared"]
user = ["mkdir -p ~/workspace"]
```
Todas las tres claves son listas de cadenas de comandos de shell. Si algún comando falla, el contenedor sale sin iniciar Firefox.

**Nota de seguridad:** Cuando `init.root` está establecido, el contenedor se inicia como root con `CAP_SETUID` y `CAP_SETGID` añadidos (además del `CAP_SYS_CHROOT` predeterminado) para poder volver a bajar al usuario normal. Estas capacidades solo se mantienen durante la fase de init como root; después de la caída de privilegios, el proceso del usuario normal no tiene capacidades adicionales. Sin `init.root`, el contenedor se ejecuta con el conjunto de capacidades mínimas predeterminado.

## Qué persiste

Sin configuración, un volumen de Podman con nombre almacena el perfil de Firefox (marcadores, ajustes, extensiones, plugin Widevine DRM). Todo lo demás es efímero.

- Cage predeterminado: `foxcage-profile`
- Cage con nombre: `foxcage-<name>-profile`

Para empezar de cero, elimina el volumen:```sh
podman volume rm foxcage-profile
```
Si `profile` está establecido, el directorio del host se monta directamente y no se crea ningún volumen.

Las extensiones listadas en `extensions` no forman parte de ese estado: viven en la imagen y se reinstalan en cada lanzamiento, por lo que eliminar el volumen (o usar una jaula efímera, que no tiene ninguno) no las pierde.

### Uso de disco

Cada imagen de jaula ocupa alrededor de 1 GB. Una reconstrucción reetiqueta la imagen y deja la anterior como una entrada `<none>` sin etiquetar, por lo que foxcage elimina la imagen que acaba de desplazar después de cada compilación exitosa. Solo elimina esa imagen específica, y nunca una que una jaula en ejecución siga usando.

Las imágenes huérfanas anteriores a este comportamiento no se limpian retroactivamente. Para recuperarlas:```sh
podman images --filter dangling=true    # review first
podman image prune                      # then remove
```
Las actualizaciones de Firefox se detectan automáticamente en cada inicio. Para forzar una reconstrucción completa (p. ej., para aplicar de inmediato las actualizaciones de seguridad del sistema):```sh
./foxcage --rebuild
```
## Temas

foxcage pasa automáticamente lo siguiente desde el host, de modo que Firefox en el contenedor se ve y se siente como una aplicación nativa:

- **Fuentes.** Las fuentes del sistema (`/usr/share/fonts`) y las fuentes de usuario (`~/.local/share/fonts`) se montan en modo solo lectura. La configuración de fuentes de `~/.config/fontconfig` también se pasa.
- **Tema GTK y modo oscuro.** Se detecta mediante `GTK_THEME` o `gsettings` y se pasa al contenedor. La configuración de GTK de `~/.config/gtk-3.0` y `~/.config/gtk-4.0` se monta en modo solo lectura.
- **Zona horaria.** El nombre de la zona horaria del host (detectado desde `TZ`, el enlace simbólico `/etc/localtime` o `/etc/timezone`) se pasa al contenedor como `TZ`, y `/etc/localtime` se monta en modo solo lectura. Ambos son necesarios: Firefox deriva la zona horaria de JavaScript a partir del *nombre* de la zona, no del contenido del archivo — sin `TZ`, los sitios web mostrarían las horas en UTC.
- **Configuración regional.** `LANG` se pasa. La configuración regional del host se genera en la imagen del contenedor en el momento de la compilación.

**Etiqueta de la jaula.** La barra de menú de Firefox muestra "FoxCage" (o "FoxCage - nombre" para jaulas con nombre) para que puedas saber de un vistazo que estás en una sesión contenerizada. La barra de menú siempre está visible mediante la política empresarial.

El contenedor solo incluye el tema GTK Adwaita. En escritorios GNOME esto funciona sin configuración adicional. En KDE u otros escritorios, Firefox recurrirá a Adwaita si tu tema GTK (p. ej. Breeze) no está instalado en el contenedor. La detección del modo oscuro sigue funcionando siempre que la preferencia esté configurada mediante `gsettings` o `GTK_THEME`.

## Decodificación de video por hardware (VA-API)

El contenedor tiene su propio espacio de usuario, por lo que los controladores VA-API instalados en el host son
irrelevantes: la imagen incluye los suyos propios. `va-driver-all` incorpora `i965-va-driver` (Intel
más antiguo) y `mesa-va-drivers` (AMD, nouveau), junto con `intel-media-va-driver-non-free`
(Intel Gen8+, el controlador iHD) y `libva2`/`libva-drm2`, que Firefox carga en tiempo de ejecución.

La decodificación por hardware necesita que se pase `/dev/dri`, algo que foxcage hace automáticamente
siempre que el host lo tenga. No hay nada que configurar.

El controlador de Intel es la compilación **no libre**, por lo que la imagen habilita el componente `non-free`
de Debian. El `intel-media-va-driver` libre de Debian es un reempaquetado `+dfsg` con los
núcleos de códec no redistribuibles eliminados, y lo que pierde es la decodificación AV1 — el formato
que YouTube sirve ahora por defecto. La compilación libre haría que AV1 recurriera al software
en todas las máquinas Intel.

Para comprobar que realmente funciona, ejecuta `vainfo` dentro de una jaula en vivo:```bash
podman exec foxcage-<name> vainfo
```
Debe listar el controlador en uso (`iHD` en Intel, `radeonsi` en AMD) y los
perfiles compatibles — `VAProfileH264*`, `VAProfileVP9Profile0`, `VAProfileAV1Profile0`, etc.
La comprobación equivalente desde el navegador es `about:support` → Media, donde la
columna Hardware Decoding debe mostrar `Supported` para H264, VP8, VP9, HEVC y AV1. Con
un video reproduciéndose, `intel_gpu_top` en el host muestra actividad en el motor de Video.

La **codificación** de hardware es independiente, y en Intel proviene del mismo controlador:
H264 y HEVC deben mostrar `Supported` en esa columna, que es lo que WebRTC usa para el
flujo saliente de la cámara en videollamadas y lo que usa `MediaRecorder`. La codificación
de VP8, VP9 y AV1 permanece `Unsupported` — Firefox solo conecta los codificadores VA-API
de H264 y HEVC, independientemente de lo que la GPU sea capaz de hacer.

Los códecs de audio (AAC, MP3, Opus, Vorbis, FLAC, Wave) muestran `Unsupported` en Hardware
Decoding en todas las máquinas — ninguna GPU de consumo tiene un bloque de decodificación
de audio. Esa fila no es una mala configuración.

Si `vainfo` informa `failed to initialize display`, el contenedor no puede abrir
`/dev/dri/renderD128`. En un escritorio systemd normal, logind concede a tu usuario una ACL
en ese dispositivo, por lo que esto suele significar que foxcage se está ejecutando desde
una sesión que no posee el asiento (SSH, una TTY diferente).

## DRM (Netflix, Disney+, etc.)

El DRM de Widevine funciona de fábrica. En la primera visita a un sitio protegido por DRM,
Firefox descargará el CDM de Widevine automáticamente. Esto puede tardar un momento.

## Integración con el host (siempre activa)

foxcage usa un proxy D-Bus filtrado para dar a Firefox acceso al portal de escritorio XDG
y al daemon de notificaciones del host. Estas funciones son seguras porque todo el acceso
está mediado por el usuario — el host muestra diálogos nativos con los que debes interactuar.
Un navegador comprometido no puede acceder silenciosamente a los recursos del host.

- **Subida de archivos** — selector de archivos nativo del host (tú eliges qué archivos compartir)
- **Enlaces externos** — `mailto:`, enlaces magnet, etc. se abren mediante el selector de aplicaciones del host
- **Notificaciones de escritorio** — reenviadas al daemon de notificaciones del host
- **Compartición de pantalla** — selector de pantalla del portal + flujo de video PipeWire (requiere PipeWire en el host)

## Paso de dispositivos (opt-in)

Estos pasan dispositivos del host directamente al contenedor y están **desactivados por
defecto** — a diferencia de las funciones del portal anteriores, no hay confirmación en el
lado del host. Un navegador comprometido podría usar el hardware silenciosamente.```toml
webcam = true          # /dev/video* — webcam for video calls
local_printers = true  # CUPS socket — USB printers (network printers work by default)
security_keys = true   # /dev/hidraw* — FIDO2/U2F hardware keys
```
## Aún no compatible

Algunas funciones de la plataforma web no funcionan en el contenedor debido a la falta de integración con el host. Estas se enumeran aquí para mayor transparencia.

**Bluetooth, USB, serie y NFC.** Las API Web Bluetooth, WebUSB, Web Serial y WebNFC requieren acceso a dispositivos y servicios del sistema (BlueZ, udev) que no están disponibles en el contenedor.

**Gamepads y MIDI.** La API Gamepad necesita acceso a `/dev/input/`. Web MIDI necesita acceso al secuenciador ALSA. Ninguno de los dos se reenvía.

**Instalación de PWA.** Las Progressive Web Apps no se pueden instalar en el escritorio del host desde dentro del contenedor.

**Accesibilidad.** El soporte de lectores de pantalla mediante AT-SPI está deshabilitado (`NO_AT_BRIDGE=1`) — el contenedor no tiene conexión con el bus de accesibilidad del host. La síntesis de voz de la Web Speech API sí funciona: `speech-dispatcher` con el motor `espeak-ng` está instalado en la jaula y se inicia automáticamente en el primer uso, con el audio enrutado a través del socket compartido de PulseAudio.

## Configuración del host

### Recomendado: almacenamiento overlay

Podman sin raíz puede recurrir al controlador de almacenamiento `vfs`, que copia capas de imagen completas en lugar de usar montajes overlay. Esto hace que el inicio del contenedor después de una compilación sea mucho más lento. Comprueba qué controlador tienes:```sh
podman info --format '{{.Store.GraphDriverName}} {{.Store.GraphStatus}}'
```
`overlay` con `Native Overlay Diff:true` es la ruta rápida y no necesita configuración: en kernel 5.13 o más reciente con un sistema de archivos subyacente ext4/xfs, Podman usa overlayfs sin privilegios directamente. Si eso es lo que ves, no hay nada que hacer, e instalar `fuse-overlayfs` no ayudará.

Solo si caes en `vfs` (kernel antiguo, o un sistema de archivos subyacente que no puede hacer overlay sin privilegios) instala `fuse-overlayfs` y añade a `~/.config/containers/storage.conf`:```toml
[storage]
driver = "overlay"

[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
```
Esto es un recurso de respaldo, no una mejora: FUSE enruta cada operación del sistema de archivos a través del espacio de usuario y es más lento que el overlay nativo. Configurar `mount_program` en un sistema que admite overlay nativo empeora las cosas, no las mejora.

### Configurar foxcage como tu navegador predeterminado

Primero, asegúrate de que el script `foxcage` esté en su ubicación permanente (por ejemplo, `~/bin/foxcage` o `/usr/local/bin/foxcage`). El comando de instalación registra la ruta actual del script en el archivo `.desktop`, por lo que moverlo después romperá el lanzador.

Luego ejecuta:```sh
foxcage --install
```
Esto crea un archivo `.desktop` que apunta a la ubicación actual del script, instala el icono de foxcage y actualiza las bases de datos del escritorio y de iconos. FoxCage debería aparecer entonces en tu menú de aplicaciones.

Para establecer foxcage como el navegador web predeterminado, de modo que los enlaces en los que se haga clic en otras aplicaciones se abran en foxcage:```sh
xdg-settings set default-web-browser foxcage.desktop
```
Si una jaula ya está en ejecución, las URLs se abren como una nueva pestaña en el navegador existente.

Para deshacer:```sh
foxcage --uninstall
```
`StartupNotify=true` está establecido en el archivo `.desktop`, lo que indica al compositor que muestre un cursor de espera mientras foxcage se inicia. Cuando se necesita una compilación de imagen (que puede tardar varios minutos), foxcage envía una notificación de escritorio para que sepas que Firefox está en camino. Cualquier error de salida temprana (error tipográfico en la configuración, dependencia faltante, nombre de jaula mal formado) también se muestra como una notificación de escritorio para que los usuarios que inician desde el escritorio no se queden mirando nada cuando foxcage falla sin una terminal adjunta. Ambos requieren `notify-send` (de `libnotify-bin` en Debian/Ubuntu) — si no está instalado, las notificaciones se omiten silenciosamente y el error aún va a stderr.

<details>
<summary>Configuración manual</summary>

Si prefieres crear el archivo `.desktop` manualmente, crea `~/.local/share/applications/foxcage.desktop`:```ini
[Desktop Entry]
Type=Application
Name=FoxCage
Comment=Firefox in a rootless Podman container
Exec=/path/to/foxcage %u
Icon=foxcage
MimeType=text/html;x-scheme-handler/http;x-scheme-handler/https;
Terminal=false
Categories=Network;WebBrowser;
StartupNotify=true
StartupWMClass=foxcage
```
Reemplaza `/path/to/foxcage` con la ruta real al script. Regístralo:```sh
update-desktop-database ~/.local/share/applications
```
</details>

## Ejecución de pruebas

El conjunto de pruebas utiliza pytest + pytest-cov, declarados como dependencias solo de desarrollo en `requirements-dev.txt`.```
pip install -r requirements-dev.txt
pytest
```
Las pruebas son totalmente herméticas: sin podman, sin red, sin sistema de archivos real más allá de `tmp_path` de pytest. El conjunto exige **100 % de cobertura de líneas y ramas** (configurado en `pytest.ini` y `.coveragerc`); cualquier línea sin cubrir, o cualquier lado no tomado de una condicional, hace fallar la ejecución. CI ejecuta el conjunto en cada push mediante `.gitlab-ci.yml`.

## Agradecimientos

Este proyecto fue desarrollado por Mike Cardwell, con la asistencia de [Claude Code](https://claude.ai/claude-code), la herramienta de codificación con IA de Anthropic.

## Apoya/Agradece mi trabajo

- [Bitcoin](bitcoin:1PQLtWnjUi1itHLG6QCQeHM3Nxua8pRsq1): 1PQLtWnjUi1itHLG6QCQeHM3Nxua8pRsq1
- [Paypal](https://www.paypal.me/grepular)
Descargar herramienta
org.freedesktop.Notifications
org.freedesktop.portal.Desktop
org.mozilla.*
org.librewolf.*
  • El acceso a portales es amplio. org.freedesktop.portal.Desktop se permite en su totalidad, porque así es como funcionan el selector de archivos, "abrir enlace en otra aplicación" y el uso compartido de pantalla. También expone RemoteDesktop (teclado/ratón sintético para toda la sesión), Camera y Location. Estos están controlados por los propios diálogos de aprobación de tu escritorio, no por foxcage — y el aviso de RemoteDesktop se parece al aviso de compartir pantalla, así que lee los diálogos de aprobación antes de aceptarlos. xdg-dbus-proxy no tiene una regla de "denegar una interfaz", así que reducir esto significa enumerar cada interfaz que Firefox necesita; consulta docs/DESIGN.md para saber por qué no se hace por defecto
  • Todos los montajes bind (profile, downloads_dir, [mounts] bind adicionales) usan nosuid,noexec
  • La descarga del navegador se verifica contra firmas GPG: Firefox contra las sumas SHA-512 firmadas de Mozilla, LibreWolf contra la firma separada de los Mantenedores de LibreWolf más SHA-256 hermano. La verificación es más estricta que gpg --verify, que sale con 0 para una firma hecha por una clave revocada y para cualquier clave en el llavero. foxcage además requiere que la firma encadene con la clave primaria fijada, y rechaza cualquier lanzamiento firmado por una subclave que su propietario haya revocado como comprometida — consulta Claves de firma revocadas
  • Contenedor efímero (--rm) — las escrituras en el sistema de archivos se pierden al salir
  • Sin dispositivos del host (cámara web, claves de seguridad, impresoras) pasados a través a menos que se habiliten explícitamente
  • Define el rango de puertos a escanear (por defecto: 1-1000).
    --verboseMuestra información detallada durante el escaneo.
    --outputEspecifica el archivo de salida para el informe.