Severity : Medium
CVSS : 5.4 (AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)
Endpoint : https://vectorbase.dev/api/notion/callback
Notion OAuth callback hardcoded to localhost — open redirect to attacker-controlled local server
Summary
The Notion OAuth callback handler redirects users to [https://localhost:3000/...](https://localhost:3000/...) in all cases because the production app's NEXT_PUBLIC_APP_URL environment variable is set to localhost:3000 instead of https://vectorbase.dev/. Any user who initiates a Notion connection is redirected to their local machine's port 3000 after the OAuth flow, which an attacker running a local server can exploit to steal the Notion workspace name and encrypted access token appended to the redirect URL.
Steps / PoC
- Observe the redirect destination without any authentication:
curl -s -D - "https://vectorbase.dev/api/notion/callback?code=test&state=dGVzdA" | grep -i location
Response:
location: https://localhost:3000/dashboard/projects?notion_error=invalid_state
- With a valid Notion OAuth
code (obtained by initiating Notion OAuth as a legitimate user), the callback executes successfully and redirects with the access token in the URL:
https://localhost:3000/dashboard/projects/<id>?notion_connected=true
&workspace_id=<id>&workspace_name=<name>&access_token=<encrypted-token>
The encrypted Notion access token is appended to the redirect URL that goes to localhost. If the victim's browser has anything listening on port 3000 (a dev server, any local app), that server receives the token in the Referer header and request path on subsequent navigations.
- The
access_token in the URL is encrypted using scrypt(ENCRYPTION_KEY, 'salt', 32). If the ENCRYPTION_KEY environment variable is not set in production (the code falls back to 'default-key-change-in-production'), the encrypted token is trivially decryptable, yielding a live Notion API token with full workspace access.
Root cause:
// src/app/api/notion/callback/route.ts
const appUrl = process.env.NEXT_PUBLIC_APP_URL // = "localhost:3000" in production
return NextResponse.redirect(
`${appUrl}/dashboard/projects/${projectId}?notion_connected=true&access_token=${encryptedToken}`
)
Impact
Users who connect Notion are redirected to localhost after completing OAuth; any service running on their local port 3000 receives the Notion access token, enabling an attacker with local server access (or a malicious local app) to steal and decrypt it.
Fix
- Set
NEXT_PUBLIC_APP_URL=https://vectorbase.dev/ in the production deployment environment.
- Never include sensitive tokens in redirect URLs; store them server-side and provide a session-scoped reference instead.
- Set
ENCRYPTION_KEY to a cryptographically random 32-byte value and use a unique per-token IV/salt rather than the static string 'salt'.
Severity : Medium
CVSS : 5.4 (AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)
Endpoint : https://vectorbase.dev/api/notion/callback
Notion OAuth callback hardcoded to localhost — open redirect to attacker-controlled local server
Summary
The Notion OAuth callback handler redirects users to
[https://localhost:3000/...](https://localhost:3000/...) in all cases because the production app'sNEXT_PUBLIC_APP_URLenvironment variable is set tolocalhost:3000instead ofhttps://vectorbase.dev/. Any user who initiates a Notion connection is redirected to their local machine's port 3000 after the OAuth flow, which an attacker running a local server can exploit to steal the Notion workspace name and encrypted access token appended to the redirect URL.Steps / PoC
Response:
code(obtained by initiating Notion OAuth as a legitimate user), the callback executes successfully and redirects with the access token in the URL:The encrypted Notion access token is appended to the redirect URL that goes to localhost. If the victim's browser has anything listening on port 3000 (a dev server, any local app), that server receives the token in the
Refererheader and request path on subsequent navigations.access_tokenin the URL is encrypted usingscrypt(ENCRYPTION_KEY, 'salt', 32). If theENCRYPTION_KEYenvironment variable is not set in production (the code falls back to'default-key-change-in-production'), the encrypted token is trivially decryptable, yielding a live Notion API token with full workspace access.Root cause:
Impact
Users who connect Notion are redirected to localhost after completing OAuth; any service running on their local port 3000 receives the Notion access token, enabling an attacker with local server access (or a malicious local app) to steal and decrypt it.
Fix
NEXT_PUBLIC_APP_URL=https://vectorbase.dev/in the production deployment environment.ENCRYPTION_KEYto a cryptographically random 32-byte value and use a unique per-token IV/salt rather than the static string'salt'.