O fluxo de ligações de chat de IA de Budibase (`GET/ POST /api/ chat- links/:instance/:token/ handoff`) liga uma **identidade externa de chat** (Slack/ Discord/MS Teams/ Telegram) a uma **conta de usuário de Budibase**. O objetivo de confirmação está em uma ** rota pública** (sem intermediário CSRF, sem portão de auth-group) e o único credencial que ele verifica é um `ConfirmationToken` que é ** já renderizado em texto plano na página de confirmação HTML** das visualizações das vítimas. Não há ligação entre o token de confirmação e a sessão Budibase do requerente no momento da preparação, e nenhum token CSRF no POST. Consequentemente, um atacante que cria uma sessão de link de chat para ** sua própria identidade de chat externo** (ou qualquer identidade que possa confetar em sua plataforma de chat) pode induzir um usuário de Budibase vítima (o mesmo inquilino) a enviar o POS de confirmação ->, por exemplo, enviando- lhes um link que se envia automaticamente, ou pelo XSS/ CSRF em uma página co- locada -> e o ` GlobalUserId ' da vítima fica ligado à identidade externa do atacante. O atacante então envia mensagens para o agente de IA a partir de sua plataforma de chat e está ** atuando como usuário da vítima** dentro de operações de automação/ agente de Budibase, herdando as permissões da vítima em operações de agente, fontes de conhecimento, e quaisquer etapas de automação a jusante tachadas fora da identidade ligada. Componentes Caminho Linhas--------------------------------------------------------------------------------------- 23 ` (`GET / api/ chat- links/:instance/:token/ handoff`), ` 27 ` (`POST.../handoff`) ї. Controlador de confirmação..................................................................................................................... 124 - 177 ` (`confirmaChatLinkSession`); a ligação em ` 153 - 173 `............................................................................................................................... 40 - 60 ` (` rendeLinkConfirmationPage`); a entrada oculta em ` 55 `.. Criação de sessão (lado de ataque)......................................................................................................................... 138 - 171 ` (`criarChatIdentityLinkSession`), ` 173 - 188 ` (`prepareChatIdentityLinkConfirmation`)....................................................................................................................... 201 - 250 ` (`upertChatIdentityLink`) ** versões afetadas:** `master` at commit ` 3 c 8 d 1 b 4023 `.

**Realizable sobre HTTP por:** o GET e o POST estão em `publicRoutes` (não há intermediário de grupo auth). O POST requer `ctx.isAuthenticated` no tempo de execução (` controllers/ai/chatIdentityLinks.ts: 142 `) -> para que a vítima deva ser logada no Budibase quando o POST dispara (alcançando-se através do CSRF padrão se os cookies forem enviados de origem cruzada, ou através de phishing que atraia a vítima a submeter). **Emissão 1 -> As rotas de entrega são públicas e não autentificadas na camada de middleware.** `` ts // pacotes/ server/src/api/routes/chat.ts: 23, 27 publicRoutes.get("/api/chat- links/:instance/:token/handoff", ai.handoffChatLinkSession) publicRoutes.post("/api/chat-links/:instance/:token/handoff", ai.confirmarChatLinkSession) ```` `publicRoutes` tem ** nenhum middleware de grupo** (`endpointGrupos/standard.ts: 24 - 25 ` chama `endpointGroupList.group()` sem intermiddleware e, em seguida, `.lockMiddleware()`. As rotas não têm um "autorizado((...)" por rota. Há ** nenhum intermediário CSRF** nestas rotas -> O símbolo de sincronização CSRF do Budibase é aplicado apenas para verbos que mudam de estado em rotas autenticadas que não estão em `NO_CSRF_ ENDPOINTS`; o caminho de rotas públicas o contorna.

**Emissão 2 -> O token de confirmação está exposto a qualquer um que veja a página GET.** `` ts // pacotes/ server/src/api/ controllers/ai/chatIdentityLinks.ts: 40 - 60 const renderLinkConfirmationPage = (sessões, ação) => {... retorna ` ... Confirm ...`} ```` O `ConfirmationToken` (um `newid()` UUIDv 4 gerado por `prepareChatIdentityLinkSessionConfirmation`) é renderizado em um formulário oculto. Qualquer pessoa que carrega a página GET vê o símbolo na fonte da página. **Emissão 3 -> O POST liga o usuário **autenticado atualmente** à identidade externa com base unicamente no token de confirmação.**.

`` ts // pacotes/ server/src/api/ controllers/ai/chatIdentityLinks.ts: 124 - 177 Exportar a função async confirmaChatLinkSession(ctx) {... se (!ctx.isAuthenticated) { lançar novo HTTPError("A autentificação é necessária para vincular a identidade do chat", 401 ) } se (!session.confirmationToken.ctx.request.body?.confirmationToken! == session.confirmationToken) { lançar novo HTTPError("A confirmação do link é inválida ou expirou", 400 ) } const currentGlobalUserId = getCurrentGlobalUserId(ctx) // <- const constedSession = get sdk.ai.chatIdentityLinks.consumChatIdentityLinkSession( token)... get sdk.ai.chatIdentityLinks.upertChatIdentityLink({ provider: consumedSession.provider, externalUserId: consumedSession.externalUserId, // <- chat identity do atacante externalUserName: consumedSession.externalUserName,... globalUserId: currentGlobalUserId, // <- vinculado à vítima vinculadoPor: actualGlobalUserId, })... } } Há ** nenhuma ligação entre a sessão e a identidade Budibase do requerente no momento da preparação**. `prepareChatIdentityLinkConfirmação de Sessão' (`sdk/workspace/ai/chatIdentityLinks.ts: 173 - 188 `) armazena o `ConfirmationToken` teclado por `token` sem campo user-id. Quem é autenticado quando o POST dispara (e fornece o `ConfirmationToken` correto) fica vinculado. **Emissão 4 -> `assisterSessionMatchesInstance` verifica apenas o ID do espaço de trabalho, não o usuário.**.

`` ts // pacotes/ server/src/api/ controllers/ai/chatIdentityLinks.ts: 17 - 27 const asserteSessionMatchesInstance = ({ workspaceId, inst }) => { se (!workspaceId ї workspaceId!== instância) { lançar um novo HTTPError("Link token não é válido para este espaço de trabalho", 400 ) } } ``` A verificação confirma que a sessão pertence ao mesmo espaço de trabalho que o URL ` instance` param -> útil para evitar confusão entre espaços de trabalho, mas inútil contra confusão de identidade do mesmo locatário. **Ataque passo a passo**. 1. **Atacker (atlant T) providencia uma sessão de chat- link para a sua própria identidade externa.** Via o fluxo de provisão de canal de agente (por exemplo, `POST /api/ agent/:agentId/ slack/ provisão` ou através dos endpoints de provisão Discord/MS Teams/ Telegram), o atacante obtém um link de chat `token` vinculado ao ** seu próprio ID de usuário Slack**. A sessão é armazenada no Redis chaveado pelo `token`, com o objetivo de T inquilino. 2. **Atacker ativa `prepareChatIdentityLinkSessionConfirmation`.** Ou através de obter a própria página de entrega (se tiverem uma sessão do Budibase) ou através de uma API interna. O `ConfirmationToken` é gerado e armazenado.

3. **Atacker faz uma página de phishing/auto- submeter** que POSTs para `/ api/ chat- links/ / / handoff` com o `token de confirmação' vazado no corpo. Exemplo: ```html "> document.getElementById('f').submit() ````. 4 **Victim (um usuário do Budibase no inquilino T, por exemplo, um administrador) é atraído para a página do atacante** enquanto está logado no Budibase. O navegador deles envia o POST cross- origin. Se o cookie de autografia do Budibase for enviado em pedidos cruzados (`SameSite=Lax` por padrão permite navegações POST de nível superior, que é um formulário- envio), o pedido é autenticado como a vítima. 5 **O `globalUserId` da vítima está agora ligado à identidade Slack do atacante.** Quando o atacante DMs o agente de AI do Slack, as operações do agente funcionam como usuário da vítima -> com permissões da vítima sobre operações de agentes, fontes de conhecimento, uploads de arquivos e quaisquer etapas de automação a jusante tachadas da identidade ligada. **Fatores de mitigação:** - `SameSite=Lax` cookies bloqueiam POSTs de sub- recursos (fetch / XHR) mas **allow** navegações de formulários- POST de nível superior. Uma página de phishing que envia o formulário via `document.form.submit()` (uma navegação de nível superior) é bem sucedida. Assim, o CSRF funciona com a política de cookie padrão. - O ataque é **same- locant only** (`session. locantId!'). context.getTenantId()` está verificado no sdk. - O atacante deve induzir a vítima a clicar num link (phishing padrão). Não há um drive-by silencioso.

Capacidade Disponível Envie mensagens ao agente de IA como usuário da vítima (Slack/Discord/MS Teams/Telegram) ▷ ▷ ▷ Objecto: Herdar as permissões da vítima nas operações do agente ▷ ▷ ▷. A gravidade depende do que o agente pode fazer como vítima. Para uma vítima de administrador, esta é a administração completa do inquilino através do chat. Para um usuário regular, é uma imitação dentro do subsistema do agente. A identidade vinculada persiste até que manualmente desligada, por isso o atacante retém o acesso em andamento. Este é um primitivo do mesmo locante, requerido pela interação do usuário. Ele está abaixo do limiar "RCE não autenticado" mas acima de "endurecimento" -> é uma vulnerabilidade real de confusão de autenticação em uma operação de ligação de identidade sensível.

** Correções recomendadas em camadas:**. 1 **Ligue o token de confirmação para a sessão Budibase do requerente no momento da preparação.** Em `prepareChatIdentityLinkSessionConfirmation`, guarde o `globalUserId' do requerente ao lado do `ConfirmationToken'. Em `confirmaChatLinkSession`, verifique que `getCurentGlobalUserId(ctx)` corresponde ao solicitante armazenado. Isto quebra a confusão entre os usuários do CSRF/. 2 **Adicione um token CSRF ao POST de confirmação.** O token CSRF sincronizador padrão do Budibase (`x- csrf- token`, validado contra o 'csrfToken' da sessão) deve ser executado no ` POST / api/ chat- links/.../ handoff'. Mova a rota para fora de `PublicRoutes` para um grupo de rotas autenticados para que a CSRF se aplique (o GET pode permanecer público para o fluxo de redirecionamento para login; o POST deve ser autenticado + protegido pela CSRF). 3 **Adicione uma nonce por sessão que está ligada ao navegador do requerente** (por exemplo, um cookie assinado no GET, validado no POST) para evitar a submissão de origem cruzada mesmo quando `SameSite=Lax' o permite.

4 **Requer reautenticação do usuário (reintrodução da senha / auth-up)** para operações de ligação de identidade sensível, semelhante a como a mudança de senha requer reauth. Registro de aconselhamento: GHSA- pvcr- 8 mvp-w 8 Qr. Não há nenhum identificador adicional listado. Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 24 T 21: 42: 51.000 Z e lista a sua última modificação como 2026 - 07 - 24 T 21: 42: 51.000 Z.

Severidade: ALTAMENTE. Dados de pontuação publicados: CVSS_V 3: CVSS: 3.1 /AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/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- 285, CWE- 345, CWE- 352. O registro contém 5 suporte de referências nestes tipos: WEB, PACKAGE.