# Budibase has an Account Impersonation Issue — Chat Identity Link Hijacking via Missing Consent & CSRF

Public GET handoff endpoint in Budibase permanently links an attacker's Slack identity to any authenticated victim's account, enabling agent impersonation.

- Payout: Research
- Severity: high
- Program: Budibase
- Found by: VishaaLlKumaaRr
- Disclosed: 2026-06-22
- CVE: CVE-2026-50132
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-v7j5-vc4m-723w
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-v7j5-vc4m-723w
- Tags: area:web domain:web impact:ato impact:privesc kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:access-control vuln:account-takeover vuln:csrf

**Target:** GET /api/chat-links/:instance/:token/handoff endpoint
**Root cause:** The handoff endpoint is registered in publicRoutes with no auth or CSRF protection and performs a permanent state-changing write binding the token's attacker-controlled externalUserId to the current session's globalUserId, with no consent UI.
**Steps:**
1. Attacker runs `/link` in Slack to the Budibase bot, obtaining a handoff URL `https://budibase.company.com/api/chat-links/ws_abc123/tok_xxxxxxxxxxxxxxxx/handoff` whose token embeds the attacker's externalUserId.
2. Attacker sends the URL to a victim (e.g. an admin) in company Slack.
3. Victim, authenticated, clicks it: `GET /api/chat-links/ws_abc123/tok_xxxxxxxxxxxxxxxx/handoff` with `Cookie: budibase:session=VICTIM_SESSION`; server writes chatidentitylink mapping attacker externalUserId to victim globalUserId and returns 'Authentication succeeded.'
4. If unauthenticated, server sets `budibase:returnurl` cookie and redirects to `/builder/auth/login`; after login the URL is revisited and the link completes.
5. Attacker messages the Slack bot from their own account; chatHandler resolves the link to the victim's globalUserId and executes agent tool calls with victim permissions.
**How found:** Code review of the publicRoutes registration for the handoff endpoint revealed a state-changing GET with no CSRF/consent, and tracing session creation showed the token embeds the attacker's own externalUserId, making the link target attacker-controlled.
**Exploitation:** Attacker generates their own link token via the `/link` slash command, socially engineers a victim into visiting the public handoff URL while authenticated, then interacts with the Budibase AI agent from their own Slack account to read rows, trigger automations, and access knowledge base files as the victim admin.
**Escalation:** Linking to an admin account grants the attacker the admin's full agent tool capabilities (row read/write, automation triggers, knowledge base access).
**Insight:** Public/unauthenticated routes that perform writes are prime CSRF targets; check whether the token/session payload is attacker-generated and whether the write binds attacker-controlled identity fields to the victim's session identity.

## Proof of concept (copied exactly from the original report)

**Victim's GET request to handoff endpoint**

```
GET /api/chat-links/ws_abc123/tok_xxxxxxxxxxxxxxxx/handoff HTTP/1.1
Host: budibase.company.com
Cookie: budibase:session=VICTIM_SESSION
```

**CouchDB link document binding attacker to victim**

```
{
  "_id": "chatidentitylink_acme_slack_T_ACME_SLACK_UA12345678",
  "tenantId": "acme",
  "provider": "slack",
  "externalUserId": "UA12345678",
  "globalUserId": "ro_global_us_VICTIM_ADMIN_ID",
  "linkedAt": "2026-05-02T10:00:42.000Z",
  "linkedBy": "ro_global_us_VICTIM_ADMIN_ID",
  "externalUserName": "attacker",
  "teamId": "T_ACME_SLACK",
  "createdAt": "2026-05-02T10:00:42.000Z",
  "updatedAt": "2026-05-02T10:00:42.000Z"
}
```

**Redis session embedding attacker's externalUserId**

```
{
  "token": "tok_xxxxxxxxxxxxxxxx",
  "tenantId": "acme",
  "workspaceId": "ws_abc123",
  "provider": "slack",
  "externalUserId": "UA12345678",
  "externalUserName": "attacker",
  "teamId": "T_ACME_SLACK",
  "createdAt": "2026-05-02T10:00:00.000Z",
  "expiresAt": "2026-05-02T10:10:00.000Z"
}
```

