fix: block impersonateUserId query param on cross-site requests to prevent CSRF

This commit is contained in:
harsh mahajan
2026-04-28 12:10:51 +05:30
parent 4c989f99c3
commit 46a457bfa3
2 changed files with 8 additions and 2 deletions
+4 -1
View File
@@ -329,7 +329,10 @@ return function (Container $container): void {
// impersonateUserId also accepts a query param to support embedding in WebSocket URLs.
// Email and phone are intentionally header-only to avoid PII exposure in proxy/LB logs.
$impersonateUserId = $request->getHeader('x-appwrite-impersonate-user-id', (string)$request->getParam('impersonateUserId', ''));
// Query-param fallback is blocked for cross-site requests to prevent CSRF attacks via
// third-party pages; Sec-Fetch-Site is a browser-enforced forbidden header.
$isCrossSite = $request->getHeader('sec-fetch-site', '') === 'cross-site';
$impersonateUserId = $request->getHeader('x-appwrite-impersonate-user-id', $isCrossSite ? '' : (string)$request->getParam('impersonateUserId', ''));
$impersonateEmail = $request->getHeader('x-appwrite-impersonate-user-email', '');
$impersonatePhone = $request->getHeader('x-appwrite-impersonate-user-phone', '');
+4 -1
View File
@@ -574,7 +574,10 @@ return function (Container $container): void {
// Impersonation: if current user has impersonator capability and headers/params are set, act as another user
// impersonateUserId also accepts a query param to allow embedding in direct file/image URLs (e.g. <img src>)
// where custom headers cannot be set. Email and phone are intentionally header-only to avoid PII in URLs/logs.
$impersonateUserId = $request->getHeader('x-appwrite-impersonate-user-id', (string)$request->getParam('impersonateUserId', ''));
// Query-param fallback is blocked for cross-site requests (Sec-Fetch-Site: cross-site) to prevent CSRF;
// Sec-Fetch-Site is a browser-enforced forbidden header that cannot be spoofed by JavaScript.
$isCrossSite = $request->getHeader('sec-fetch-site', '') === 'cross-site';
$impersonateUserId = $request->getHeader('x-appwrite-impersonate-user-id', $isCrossSite ? '' : (string)$request->getParam('impersonateUserId', ''));
$impersonateEmail = $request->getHeader('x-appwrite-impersonate-user-email', '');
$impersonatePhone = $request->getHeader('x-appwrite-impersonate-user-phone', '');
if (!$user->isEmpty() && $user->getAttribute('impersonator', false)) {