Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions src/routes/oauth/authorize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ import { useIsDark } from '~/hooks/useIsDark'
import { BrandContextMenu } from '~/components/BrandContextMenu'

/**
* Validate redirect URI - must be localhost or HTTPS
* Validate redirect URI - block only HTTP to non-localhost
* Allows: HTTPS, localhost (any protocol), custom schemes (cursor://, vscode://, etc.)
* Inlined here to avoid pulling in server-only dependencies
*/
function validateRedirectUri(uri: string): boolean {
try {
const url = new URL(uri)
if (
url.hostname === 'localhost' ||
url.hostname === '127.0.0.1' ||
url.hostname === '[::1]'
) {
return true
// Block only HTTP to non-localhost
if (url.protocol === 'http:') {
return (
url.hostname === 'localhost' ||
url.hostname === '127.0.0.1' ||
url.hostname === '[::1]'
)
}
if (url.protocol === 'https:') {
return true
}
return false
// Allow everything else: HTTPS, custom schemes
return true
} catch {
return false
}
Expand Down Expand Up @@ -84,7 +84,7 @@ export const Route = createFileRoute('/oauth/authorize')({
if (!validateRedirectUri(deps.redirect_uri)) {
return {
error: 'invalid_request',
errorDescription: 'redirect_uri must be localhost or HTTPS',
errorDescription: 'HTTP redirect URIs are only allowed for localhost',
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/routes/oauth/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const Route = createFileRoute('/oauth/register')({
// This is secure because:
// 1. Registration only generates deterministic client IDs
// 2. No secrets are issued (PKCE public clients)
// 3. Redirect URIs are validated for localhost or HTTPS
// 3. Redirect URIs block insecure HTTP to remote hosts
const origin = request.headers.get('Origin')
setResponseHeader('Content-Type', 'application/json')
setResponseHeader('Access-Control-Allow-Origin', origin || '*')
Expand All @@ -41,14 +41,14 @@ export const Route = createFileRoute('/oauth/register')({
url.hostname === 'localhost' ||
url.hostname === '127.0.0.1' ||
url.hostname === '[::1]'
const isHttps = url.protocol === 'https:'

if (!isLocalhost && !isHttps) {
// Block only HTTP to non-localhost (allows custom schemes like cursor://)
if (url.protocol === 'http:' && !isLocalhost) {
return new Response(
JSON.stringify({
error: 'invalid_redirect_uri',
error_description:
'Redirect URIs must be localhost or HTTPS',
'HTTP redirect URIs are only allowed for localhost',
}),
{ status: 400 },
)
Expand Down