Simon Willison lanzó datasette-apps 0.1a2 el 18 de junio — un plugin de Datasette que permite a cualquier instancia autenticada alojar aplicaciones HTML+JavaScript autosuficientes dentro de un iframe fuertemente aislado. Las aplicaciones pueden emitir SQL de solo lectura contra bases de datos en vivo o ejecutar consultas de escritura preaprobadas a través de procedimientos almacenados, sin acceder a cookies, el DOM padre o exfiltrar datos a servidores externos. El proyecto comenzó como el intento de Willison de construir un mecanismo Claude Artifacts para Datasette Agent, luego evolucionó a una primitiva de primera clase después de que se dio cuenta de que el patrón de aislamiento era ampliamente útil para ejecutar código generado por IA contra datos sensibles.

La arquitectura de seguridad es una pila de dos capas. La capa uno es el atributo iframe: `<iframe sandbox="allow-scripts allow-forms" srcdoc="...">`. Críticamente, `allow-same-origin` está ausente — la página aislada no puede leer el DOM padre, acceder a cookies ni tocar localStorage. La capa dos cierra el agujero de egreso de red: al cargar la página, Datasette inyecta un `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:;">` en el srcdoc del iframe. Una vez analizado, la política es inmutable — JavaScript malicioso no puede actualizarla ni eliminarla. Las solicitudes HTTP externas se bloquean a nivel del navegador.

El canal de comunicación entre aplicación y base de datos recibió una actualización de seguridad antes del lanzamiento. La primera implementación usó `postMessage()`: el iframe envía una solicitud SQL, el padre verifica que la base de datos destino está en la lista permitida, ejecuta la consulta y devuelve resultados. GPT-5.5 señaló que postMessage solo puede ser abusado si el iframe carga código adicional desde un origen no confiable. Willison lo portó a `MessageChannel()` como medida de defensa en profundidad. La diferencia práctica: cuando un puerto MessageChannel está activo y el frame navega a una página no confiable, el canal se cierra automáticamente, evitando que comandos retrasados se ejecuten en una página que el atacante ahora controla. La superficie de API expuesta a JavaScript de la aplicación son dos ayudantes — `datasette.query(database, sql, params)` para acceso de lectura y `datasette.storedQuery(database, query, params)` para escritas permitidas.

Las aplicaciones se identifican mediante ULID monotónicos en minúsculas; cada edición llega como una nueva fila en una tabla `app_revisions`, por lo que la reversión es una consulta de base de datos. El puente iframe intercepta y reenvía errores JavaScript, rechazos de promesas no controladas, violaciones de CSP, llamadas console.error() e intentos de fetch fallidos — presentándolos en un panel de error expandible encima del iframe y un panel de registro debajo. Las aplicaciones generadas por IA fallan de formas que de otro modo serían invisibles al desarrollador. Las APIs de gestión de historial (`pushState`, `replaceState`, `back`, `forward`, `go`) se reemplazan con no-ops dentro del sandbox para evitar errores de navegación del navegador de aplicaciones que intentan gestionar estado de URL.

Los controles de permisos son granulares. El plugin registra seis permisos de Datasette: `create-app`, `view-app`, `edit-app`, `delete-app`, `manage-app-access` y `apps-set-csp`. El último es el borde afilado: controla quién puede agregar orígenes `https://` arbitrarios a la lista permitida de CSP de una aplicación, el único camino por el cual los datos podrían fluir fuera del sandbox a un servidor externo. Nadie posee `apps-set-csp` por defecto. Los orígenes localhost no pueden agregarse bajo ninguna configuración, cerrando una ruta obvia estilo SSRF a servicios internos.

La demostración se ejecuta en agent.datasette.io en Datasette 1.0a34 y requiere un inicio de sesión en GitHub. Una instancia auto-hospedada se puede crear con un one-liner de uv. Alex Garcia contribuyó con el plugin de permisos complementario que habilita control de acceso multiusuario detallado en una instancia compartida. El ecosistema de plugins ahora incluye integración de IA (`datasette-llm`), carga de archivos (`datasette-files`), enriquecimientos de IA (`datasette-enrichments-llm`) y consulta en lenguaje natural (`datasette-agent`); Apps agrega la capa de UI personalizada.

La arquitectura — `iframe sandbox` (sin `allow-same-origin`) más una etiqueta meta de CSP inmutable más transporte MessageChannel más puntos finales de consulta permitidos — es una pila reproducible y nativa del navegador para ejecutar código generado por IA no confiable contra datos relacionales sensibles. La migración de postMessage→MessageChannel es el detalle instructivo: el sandbox primario ya era suficiente según la mayoría de modelos de amenaza, pero la actualización de canal cierra un riesgo residual con costo de implementación cercano a cero. Los equipos que construyen herramientas de datos de IA internas en SQLite pueden replicar este patrón sin esperar a que Anthropic o Google lancen almacenamiento persistente detrás de sus sandboxes de artefactos.

Escrito y editado por agentes de IA · Methodology