Simon Willison lançou datasette-apps 0.1a2 em 18 de junho — um plugin de Datasette que permite a qualquer instância autenticada hospedar aplicações HTML+JavaScript autossuficientes dentro de um iframe rigorosamente isolado. Os aplicativos podem emitir SQL somente leitura contra bancos de dados em tempo real ou executar consultas de escrita pré-aprovadas via procedimentos armazenados, sem acessar cookies, o DOM pai ou exfiltrar dados para servidores externos. O projeto começou como a tentativa de Willison de construir um mecanismo Claude Artifacts para Datasette Agent, depois evoluiu para uma primitiva de primeira classe após ele perceber que o padrão de isolamento era amplamente útil para executar código gerado por IA contra dados sensíveis.

A arquitetura de segurança é uma pilha de duas camadas. A camada um é o atributo iframe: `<iframe sandbox="allow-scripts allow-forms" srcdoc="...">`. Criticamente, `allow-same-origin` está ausente — a página isolada não pode ler o DOM pai, acessar cookies ou tocar localStorage. A camada dois lacra o buraco de saída de rede: no carregamento da página, Datasette injeta um `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:;">` no srcdoc do iframe. Uma vez analisada, a política é imutável — JavaScript malicioso não pode atualizá-la ou removê-la. Requisições HTTP externas são bloqueadas no nível do navegador.

O canal de comunicação entre aplicativo e banco de dados recebeu uma atualização de segurança antes do lançamento. A primeira implementação usou `postMessage()`: o iframe envia uma requisição SQL, o pai verifica se o banco de dados alvo está na lista de permissões, executa a consulta e retorna os resultados. GPT-5.5 sinalizou que postMessage sozinho pode ser abusado se o iframe carregasse código adicional de uma origem não confiável. Willison portou para `MessageChannel()` como uma medida de defesa em profundidade. A diferença prática: quando uma porta MessageChannel está ativa e o frame navega para uma página não confiável, o canal fecha automaticamente, impedindo que comandos atrasados sejam executados em uma página que o atacante agora controla. A superfície de API exposta ao JavaScript do aplicativo é dois auxiliares — `datasette.query(database, sql, params)` para acesso de leitura e `datasette.storedQuery(database, query, params)` para escritas permitidas.

Apps são identificados por ULIDs monotônicos em minúsculas; cada edição chega como uma nova linha em uma tabela `app_revisions`, então reversão é uma consulta de banco de dados. A ponte iframe intercepta e encaminha erros JavaScript, rejeições de promessas não tratadas, violações de CSP, chamadas de console.error() e tentativas de fetch falhadas — exibindo-as em um painel de erro expansível acima do iframe e um painel de log abaixo. Apps gerados por IA falham de maneiras que são invisíveis ao desenvolvedor. APIs de gerenciamento de histórico (`pushState`, `replaceState`, `back`, `forward`, `go`) são substituídas por no-ops dentro do sandbox para evitar erros de navegação do navegador de aplicativos que tentam gerenciar estado de URL.

Os controles de permissão são granulares. O plugin registra seis permissões de Datasette: `create-app`, `view-app`, `edit-app`, `delete-app`, `manage-app-access` e `apps-set-csp`. A última é a borda afiada: controla quem pode adicionar origens `https://` arbitrárias à lista de permissões de CSP de um aplicativo, o único caminho pelo qual dados poderiam sair do sandbox para um servidor externo. Ninguém possui `apps-set-csp` por padrão. Origens localhost não podem ser adicionadas sob nenhuma configuração, fechando uma rota óbvia estilo SSRF para serviços internos.

A demonstração funciona em agent.datasette.io em Datasette 1.0a34 e requer um login no GitHub. Uma instância auto-hospedada pode ser criada com um one-liner de uv. Alex Garcia contribuiu com o plugin de permissões complementar que habilita controle de acesso multi-usuário refinado em uma instância compartilhada. O ecossistema de plugins agora inclui integração com IA (`datasette-llm`), upload de arquivos (`datasette-files`), enriquecimentos de IA (`datasette-enrichments-llm`) e consulta em linguagem natural (`datasette-agent`); Apps adiciona a camada de UI customizada.

A arquitetura — `iframe sandbox` (sem `allow-same-origin`) mais uma tag meta de CSP imutável mais transporte MessageChannel mais endpoints de consulta permitidos — é uma pilha reproducível e nativa do navegador para executar código gerado por IA não confiável contra dados relacionais sensíveis. A migração de postMessage→MessageChannel é o detalhe instrutivo: o sandbox primário já era suficiente pela maioria dos modelos de ameaça, mas a atualização de canal fecha um risco residual com custo de implementação próximo a zero. Equipes construindo ferramentas de dados de IA internas em SQLite podem replicar este padrão sem esperar pela Anthropic ou Google para disponibilizarem armazenamento persistente atrás de seus sandboxes de artefatos.