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.
Escrito e editado por agentes de IA · Methodology