{"id":"CVE-2026-48151","aliases":["EUVD-2026-32589","GHSA-qhv3-wjg8-6fx6"],"status":"published","title":"Budibase: Webhook schema endpoint authorization bypass allows unauthenticated mutation of webhook and automation schema","description":"Budibase is an open-source low-code platform. Prior to 3.39.0, the webhook schema-building endpoint is registered under builderRoutes, but the generic authorization middleware skips authorization for all paths matching /api/webhooks/schema. As a result, an unauthenticated caller can update the body schema for a known webhook and mutate the corresponding automation trigger output schema. This vulnerability is fixed in 3.39.0.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00224,"percentile":0.13094,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-862"],"published":"2026-05-27T16:57:36Z","modified":"2026-10-28T02:31:10Z","fixes":[{"ecosystem":"npm","package":"@budibase/server","fixed_in":["3.39.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"@budibase/server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.39.0"}]}]},{"source":"osv","ecosystem":"npm","package":"@budibase/server","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"3.39.0"}]}]}],"products":[{"vendor":"budibase","product":"budibase"}],"references":[{"url":"https://github.com/Budibase/budibase/security/advisories/GHSA-qhv3-wjg8-6fx6","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-48151","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-qhv3-wjg8-6fx6"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/48xxx/CVE-2026-48151.json","tags":["advisory"]},{"url":"https://github.com/Budibase/budibase","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-48151","title":"Budibase: Webhook schema endpoint authorization bypass allows unauthenticated mutation of webhook and automation schema","description":"Budibase is an open-source low-code platform. Prior to 3.39.0, the webhook schema-building endpoint is registered under builderRoutes, but the generic authorization middleware skips authorization for all paths matching /api/webhooks/schema. As a result, an unauthenticated caller can update the body schema for a known webhook and mutate the corresponding automation trigger output schema. This vulnerability is fixed in 3.39.0.","status":"published","published":"2026-05-27T16:57:36.447Z","modified":"2026-05-28T14:12:26.911Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high","assessor":"cna"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T14:19:47.998488Z"}],"euvd":[{"id":"EUVD-2026-32589","description":"Budibase is an open-source low-code platform. Prior to 3.39.0, the webhook schema-building endpoint is registered under builderRoutes, but the generic authorization middleware skips authorization for all paths matching /api/webhooks/schema. As a result, an unauthenticated caller can update the body schema for a known webhook and mutate the corresponding automation trigger output schema. This vulnerability is fixed in 3.39.0.","status":"published","published":"2026-05-27T16:57:36Z","modified":"2026-05-28T14:12:26Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high"}],"updated_at":"2026-11-02T18:21:02.581093Z"}],"ghsa":[{"id":"GHSA-qhv3-wjg8-6fx6","title":"Budibase: Webhook schema endpoint authorization bypass allows unauthenticated mutation of webhook and automation schema","description":"The webhook schema-building endpoint is registered under `builderRoutes`, but the generic authorization middleware skips authorization for all paths matching `/api/webhooks/schema`. As a result, an unauthenticated caller can update the body schema for a known webhook and mutate the corresponding automation trigger output schema.\n\n### Details\n\nThe route appears to be builder-only:\n\n- `packages/server/src/api/routes/webhook.ts:5-9`\n\n```ts\n5:builderRoutes\n6:  .get(\"/api/webhooks\", controller.fetch)\n7:  .put(\"/api/webhooks\", webhookValidator(), controller.save)\n8:  .delete(\"/api/webhooks/:id/:rev\", controller.destroy)\n9:  .post(\"/api/webhooks/schema/:instance/:id\", controller.buildSchema)\n```\n\nHowever, webhook endpoint detection explicitly includes `schema`:\n\n- `packages/server/src/middleware/utils.ts:3-9`\n\n```ts\n3:const WEBHOOK_ENDPOINTS = new RegExp(\n4:  \"^/api/webhooks/(trigger|schema|discord|ms-teams|slack)(/|$)\"\n5:)\n6:\n7:export function isWebhookEndpoint(ctx: UserCtx): boolean {\n8:  const path = ctx.path || ctx.request.url.split(\"?\")[0]\n9:  return WEBHOOK_ENDPOINTS.test(path)\n```\n\nThe authorization middleware bypasses all webhook endpoints before checking `ctx.user` or permissions:\n\n- `packages/server/src/middleware/authorized.ts:90-99`\n\n```ts\n90:  ) =\u003e\n91:  async (ctx: UserCtx, next: any) =\u003e {\n92:    // webhooks don't need authentication, each webhook unique\n93:    // also internal requests (between services) don't need authorized\n94:    if (isWebhookEndpoint(ctx) || ctx.internal) {\n95:      return next()\n96:    }\n97:\n98:    if (!ctx.user) {\n99:      return ctx.throw(401, \"No user info found\")\n```\n\nThe bypassed controller writes attacker-derived schema data to the webhook and automation trigger outputs:\n\n- `packages/server/src/api/controllers/webhook.ts:56-83`\n\n```ts\n56:export async function buildSchema(\n57:  ctx: Ctx\u003cBuildWebhookSchemaRequest, BuildWebhookSchemaResponse\u003e\n58:) {\n59:  await context.doInWorkspaceContext(ctx.params.instance, async () =\u003e {\n60:    const db = context.getWorkspaceDB()\n61:    const webhook = await db.get\u003cWebhook\u003e(ctx.params.id)\n62:    webhook.bodySchema = toJsonSchema(ctx.request.body)\n63:    // update the automation outputs\n64:    if (webhook.action.type === WebhookActionType.AUTOMATION) {\n65:      let automation = await db.get\u003cAutomation\u003e(webhook.action.target)\n66:      const autoOutputs = automation.definition.trigger.schema.outputs\n67:      let properties = webhook.bodySchema?.properties\n68:      // reset webhook outputs\n69:      autoOutputs.properties = {\n70:        body: autoOutputs.properties.body,\n71:      }\n72:      for (let prop of Object.keys(properties || {})) {\n73:        if (properties?.[prop] == null) {\n74:          continue\n75:        }\n76:        const def = properties[prop]\n77:        if (typeof def === \"boolean\") {\n78:          continue\n79:        }\n80:        autoOutputs.properties[prop] = {\n81:          type: def.type as AutomationIOType,\n82:          description: AUTOMATION_DESCRIPTION,\n83:        }\n```\n\nThe route grouping suggests builder authorization was intended, but the global webhook bypass removes it.\n\n### PoC\n\nNon-destructive validation approach:\n\n1. Create a webhook-backed automation as a builder.\n2. Record the workspace ID and webhook ID.\n3. Log out or send no auth headers.\n4. Send:\n\n```http\nPOST /api/webhooks/schema/\u003cworkspaceId\u003e/\u003cwebhookId\u003e HTTP/1.1\ncontent-type: application/json\n\n{\"unauth_schema_probe\":\"test\"}\n```\n\n5. Fetch the webhook as a builder and observe that `bodySchema` has changed.\n6. For automation-backed webhooks, inspect the automation trigger schema outputs and observe that properties were reset/updated.\n\n### Impact\n\nAn unauthenticated attacker can modify webhook schema metadata and automation trigger output schema for known webhook IDs. This can corrupt builder-visible automation definitions, alter downstream binding behavior, and disrupt webhook-backed automation workflows.","status":"published","published":"2026-06-12T18:28:34Z","modified":"2026-06-12T18:28:35Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T14:40:26.12116Z"}],"nvd":[{"id":"CVE-2026-48151","description":"Budibase is an open-source low-code platform. Prior to 3.39.0, the webhook schema-building endpoint is registered under builderRoutes, but the generic authorization middleware skips authorization for all paths matching /api/webhooks/schema. As a result, an unauthenticated caller can update the body schema for a known webhook and mutate the corresponding automation trigger output schema. This vulnerability is fixed in 3.39.0.","status":"published","published":"2026-05-27T18:16:27.593Z","modified":"2026-06-17T10:54:53.923Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high","assessor":"secondary"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T14:12:20.885865Z"}],"osv":[{"id":"CVE-2026-48151","title":"Budibase: Webhook schema endpoint authorization bypass allows unauthenticated mutation of webhook and automation schema","description":"Budibase is an open-source low-code platform. Prior to 3.39.0, the webhook schema-building endpoint is registered under builderRoutes, but the generic authorization middleware skips authorization for all paths matching /api/webhooks/schema. As a result, an unauthenticated caller can update the body schema for a known webhook and mutate the corresponding automation trigger output schema. This vulnerability is fixed in 3.39.0.","status":"published","published":"2026-05-27T16:57:36.447Z","modified":"2026-10-28T02:31:10.343369913Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T15:45:06.701612Z"},{"id":"GHSA-qhv3-wjg8-6fx6","title":"Budibase: Webhook schema endpoint authorization bypass allows unauthenticated mutation of webhook and automation schema","description":"The webhook schema-building endpoint is registered under `builderRoutes`, but the generic authorization middleware skips authorization for all paths matching `/api/webhooks/schema`. As a result, an unauthenticated caller can update the body schema for a known webhook and mutate the corresponding automation trigger output schema.\n\n### Details\n\nThe route appears to be builder-only:\n\n- `packages/server/src/api/routes/webhook.ts:5-9`\n\n```ts\n5:builderRoutes\n6:  .get(\"/api/webhooks\", controller.fetch)\n7:  .put(\"/api/webhooks\", webhookValidator(), controller.save)\n8:  .delete(\"/api/webhooks/:id/:rev\", controller.destroy)\n9:  .post(\"/api/webhooks/schema/:instance/:id\", controller.buildSchema)\n```\n\nHowever, webhook endpoint detection explicitly includes `schema`:\n\n- `packages/server/src/middleware/utils.ts:3-9`\n\n```ts\n3:const WEBHOOK_ENDPOINTS = new RegExp(\n4:  \"^/api/webhooks/(trigger|schema|discord|ms-teams|slack)(/|$)\"\n5:)\n6:\n7:export function isWebhookEndpoint(ctx: UserCtx): boolean {\n8:  const path = ctx.path || ctx.request.url.split(\"?\")[0]\n9:  return WEBHOOK_ENDPOINTS.test(path)\n```\n\nThe authorization middleware bypasses all webhook endpoints before checking `ctx.user` or permissions:\n\n- `packages/server/src/middleware/authorized.ts:90-99`\n\n```ts\n90:  ) =\u003e\n91:  async (ctx: UserCtx, next: any) =\u003e {\n92:    // webhooks don't need authentication, each webhook unique\n93:    // also internal requests (between services) don't need authorized\n94:    if (isWebhookEndpoint(ctx) || ctx.internal) {\n95:      return next()\n96:    }\n97:\n98:    if (!ctx.user) {\n99:      return ctx.throw(401, \"No user info found\")\n```\n\nThe bypassed controller writes attacker-derived schema data to the webhook and automation trigger outputs:\n\n- `packages/server/src/api/controllers/webhook.ts:56-83`\n\n```ts\n56:export async function buildSchema(\n57:  ctx: Ctx\u003cBuildWebhookSchemaRequest, BuildWebhookSchemaResponse\u003e\n58:) {\n59:  await context.doInWorkspaceContext(ctx.params.instance, async () =\u003e {\n60:    const db = context.getWorkspaceDB()\n61:    const webhook = await db.get\u003cWebhook\u003e(ctx.params.id)\n62:    webhook.bodySchema = toJsonSchema(ctx.request.body)\n63:    // update the automation outputs\n64:    if (webhook.action.type === WebhookActionType.AUTOMATION) {\n65:      let automation = await db.get\u003cAutomation\u003e(webhook.action.target)\n66:      const autoOutputs = automation.definition.trigger.schema.outputs\n67:      let properties = webhook.bodySchema?.properties\n68:      // reset webhook outputs\n69:      autoOutputs.properties = {\n70:        body: autoOutputs.properties.body,\n71:      }\n72:      for (let prop of Object.keys(properties || {})) {\n73:        if (properties?.[prop] == null) {\n74:          continue\n75:        }\n76:        const def = properties[prop]\n77:        if (typeof def === \"boolean\") {\n78:          continue\n79:        }\n80:        autoOutputs.properties[prop] = {\n81:          type: def.type as AutomationIOType,\n82:          description: AUTOMATION_DESCRIPTION,\n83:        }\n```\n\nThe route grouping suggests builder authorization was intended, but the global webhook bypass removes it.\n\n### PoC\n\nNon-destructive validation approach:\n\n1. Create a webhook-backed automation as a builder.\n2. Record the workspace ID and webhook ID.\n3. Log out or send no auth headers.\n4. Send:\n\n```http\nPOST /api/webhooks/schema/\u003cworkspaceId\u003e/\u003cwebhookId\u003e HTTP/1.1\ncontent-type: application/json\n\n{\"unauth_schema_probe\":\"test\"}\n```\n\n5. Fetch the webhook as a builder and observe that `bodySchema` has changed.\n6. For automation-backed webhooks, inspect the automation trigger schema outputs and observe that properties were reset/updated.\n\n### Impact\n\nAn unauthenticated attacker can modify webhook schema metadata and automation trigger output schema for known webhook IDs. This can corrupt builder-visible automation definitions, alter downstream binding behavior, and disrupt webhook-backed automation workflows.","status":"published","published":"2026-06-12T18:28:34Z","modified":"2026-09-10T03:50:50.242075225Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T15:46:54.760124Z"}]}}
