# NocoDB: Stored Cross-Site Scripting via Form View Redirect URL

Editor-planted javascript: redirect_url in NocoDB form view bypasses same-host check, executing same-origin on submit and stealing viewer's localStorage session token.

- Payout: Research
- Severity: high
- Program: NocoDB
- Found by: kah-ja
- Disclosed: 2026-06-05
- CVE: CVE-2026-47387
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-hj85-ph9q-78jg
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-hj85-ph9q-78jg
- Tags: area:web domain:web impact:ato impact:data-leak kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:xss

**Target:** Shared form-view submit handler (useSharedFormViewStore.ts) and form-view PATCH endpoint
**Root cause:** isValidRedirectUrl only checked string type and non-empty trim, no scheme validation; the same-host check compared anchor.host to window.location.host, but non-network schemes like javascript:/data:/vbscript:/file: yield an empty anchor.host, so the check fails and the code falls into the external-redirect branch assigning window.location.href.
**Steps:**
1. As a user with editor role on a base, PATCH the form-view redirect_url to a `javascript:` payload.
2. Confirm the public shared-view meta endpoint returns the value verbatim.
3. Distribute the form share-link to an authenticated viewer.
4. Viewer submits the form (optionally reduced to one click via a hidden pre-filled required field).
5. Submit handler builds anchor, anchor.host is empty for javascript:, same-host check false, falls to `window.location.href = redirectUrl`, payload executes same-origin.
6. Payload reads `localStorage["nocodb-gui-v2"].token` and exfiltrates it.
**How found:** Code review of the shared form-view submit handler: noticed isValidRedirectUrl lacked a scheme check and that the same-host comparison via anchor.host would be empty for non-network schemes, routing them to the external-redirect branch.
**Exploitation:** Attacker with editor role plants a javascript: URL in redirect_url, shares the on-brand form link, and on viewer submit the payload runs in the NocoDB origin, reads the session token from localStorage, and uses it to call authenticated APIs as the viewer scoped to their permissions.
**Escalation:** Stolen token enables authenticated API calls under the viewer's identity across their permitted workspaces, bases, and operations.
**Insight:** When a redirect guard compares anchor.host to window.location.host, remember anchor.host is empty for javascript:/data:/vbscript:/file: schemes — an empty-vs-empty or empty-vs-host mismatch silently routes dangerous schemes into the redirect sink; always allowlist http/https explicitly.

