GitHub Security Advisory: GHSA-rvhr-26g4-p2r8
Package: budibase (NPM)
Severity: CRITICAL (CVSS 9.9)
CWE: CWE-20: Improper Input Validation, CWE-94: Improper Control of Generation of Code ('Code Injection'), CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
Vulnerable versions: < 3.30.4
Patched in: 3.30.4

Summary: Budibase: Remote Code Execution via Unsafe eval() in View Filter Map Function (Budibase Cloud)

Details:
## Summary

A critical unsafe `eval()` vulnerability in Budibase's view filtering implementation allows any authenticated user (including free tier accounts) to execute arbitrary JavaScript code on the server. **This vulnerability ONLY affects Budibase Cloud (SaaS)** - self-hosted deployments use native CouchDB views and are not vulnerable. The vulnerability exists in `packages/server/src/db/inMemoryView.ts` where user-controlled view map functions are directly evaluated without sanitization.

The primary impact comes from what lives inside the pod's environment: the `app-service` pod runs with **secrets baked into its environment variables**, including `INTERNAL_API_KEY`, `JWT_SECRET`, CouchDB admin credentials, AWS keys, and more. Using the extracted CouchDB credentials, we verified direct database access, enumerated all tenant databases, and confirmed that user records (email addresses) are readable.

## Details

### Root Cause

File: `packages/server/src/db/inMemoryView.ts:28`

```javascript
export async function runView(
  view: DBView,
  calculation: string,
  group: boolean,
  data: Row[]
) {
  // ...
  let fn = (doc: Document, emit: any) => emit(doc._id)
  // BUDI-7060 -> indirect eval call appears to cause issues in cloud
  eval("fn = " + view?.map?.replace("function (doc)", "function (doc, emit)"))  // UNSAFE EVAL
  // ...
}
```

**Why Only Cloud is Vulnerable:**

File: `packages/server/src/sdk/workspace/rows/search/internal/internal.ts:194-221`

```typescript
if (env.SELF_HOSTED) {
  // Self-hosted: Uses native CouchDB design documents - NO EVAL
  response = await db.query(`database/${viewName}`, {
    include_docs: !calculation,
    group: !!group,
  })
} else {
  // Cloud: Uses in-memory PouchDB with UNSAFE EVAL
  const tableId = viewInfo.meta!.tableId
  const data = await fetchRaw(tableId!)
  response = await inMemoryViews.runView(  // <- Calls vulnerable function
    viewInfo,
    calculation as string,
    !!group,
    data
  )
}
```

The `view.map` parameter comes directly from user input when creating table views with filters. The code constructs a string by concatenating `"fn = "` with the user-controlled map function and passes it to `eval()`, allowing arbitrary JavaScript execution in the Node.js server context.

**Self-hosted deployments are not affected** because they use native CouchDB design documents instead of the in-memory eval() path.

### Attack Flow

1. Authenticated user creates a table view with custom filter
2. Frontend sends POST request to `/api/views` with malicious payload in filter value
3. Backend stores view configuration in CouchDB
4. When view is queried (GET `/api/views/{viewName}`), `runView()` is called
5. Malicious code is `eval()`'d on server - RCE achieved

### Exploitation Vector

The vulnerability is triggered via the view filter mechanism. When creating a view with a filter condition, the filter value can be injected with JavaScript code that breaks out of the intended expression context:

**Mal