fix: prevent OIDC redirect URI construction from untrusted X-Forwarded-Host
The OIDC login route silently fell back to building the redirect URI from X-Forwarded-Host/X-Forwarded-Proto when APP_URL was not configured. An attacker could set X-Forwarded-Host: attacker.example.com to redirect the authorization code to their own server after the user authenticates. Remove the header-derived fallback entirely. If APP_URL is not set (via env or the app_url DB setting), the OIDC login endpoint now returns a 500 error rather than trusting attacker-controlled request headers. Document APP_URL in .env.example as required for OIDC use.
This commit is contained in:
@@ -8,6 +8,8 @@ ALLOWED_ORIGINS=https://trek.example.com # Comma-separated origins for CORS and
|
||||
FORCE_HTTPS=false # Redirect HTTP → HTTPS behind a TLS proxy
|
||||
TRUST_PROXY=1 # Number of trusted proxies for X-Forwarded-For
|
||||
|
||||
APP_URL=https://trek.example.com # Base URL of this instance — required when OIDC is enabled; must match the redirect URI registered with your IdP
|
||||
|
||||
OIDC_ISSUER=https://auth.example.com # OpenID Connect provider URL
|
||||
OIDC_CLIENT_ID=trek # OpenID Connect client ID
|
||||
OIDC_CLIENT_SECRET=supersecret # OpenID Connect client secret
|
||||
|
||||
@@ -123,14 +123,10 @@ router.get('/login', async (req: Request, res: Response) => {
|
||||
const doc = await discover(config.issuer);
|
||||
const state = crypto.randomBytes(32).toString('hex');
|
||||
const appUrl = process.env.APP_URL || (db.prepare("SELECT value FROM app_settings WHERE key = 'app_url'").get() as { value: string } | undefined)?.value;
|
||||
let redirectUri: string;
|
||||
if (appUrl) {
|
||||
redirectUri = `${appUrl.replace(/\/+$/, '')}/api/auth/oidc/callback`;
|
||||
} else {
|
||||
const proto = (req.headers['x-forwarded-proto'] as string) || req.protocol;
|
||||
const host = (req.headers['x-forwarded-host'] as string) || req.headers.host;
|
||||
redirectUri = `${proto}://${host}/api/auth/oidc/callback`;
|
||||
if (!appUrl) {
|
||||
return res.status(500).json({ error: 'APP_URL is not configured. OIDC cannot be used.' });
|
||||
}
|
||||
const redirectUri = `${appUrl.replace(/\/+$/, '')}/api/auth/oidc/callback`;
|
||||
const inviteToken = req.query.invite as string | undefined;
|
||||
|
||||
pendingStates.set(state, { createdAt: Date.now(), redirectUri, inviteToken });
|
||||
|
||||
Reference in New Issue
Block a user