-
Notifications
You must be signed in to change notification settings - Fork 110
Description
[Security] Add redirect loop protection to AuthenticationService
Summary
The AuthenticationService::getLoginRedirect() method is vulnerable to redirect loop attacks where malicious actors or misconfigured bots can create deeply nested redirect chains that waste server resources and potentially enable security exploits.
Current Behavior
When an unauthenticated user tries to access a protected page, the authentication middleware redirects them to the login page with a redirect query parameter containing the original URL:
GET /protected/page → 302 Redirect to /login?redirect=/protected/page
However, the getLoginRedirect() method (lines 433-461 in src/AuthenticationService.php) only validates that the redirect URL:
- Is not empty
- Doesn't contain a host or scheme (prevents external redirects)
- Starts with
/
It does NOT check for:
- ❌ Recursive redirect parameters
- ❌ Multiple encoding levels
- ❌ Redirecting back to authentication-related pages
Vulnerability Example
A bot or attacker can create URLs like:
/login?redirect=/login?redirect=/login?redirect=/protected/page
Which when URL-encoded becomes:
/login?redirect=%2Flogin%3Fredirect%3D%252Flogin%253Fredirect%253D%25252Fprotected%25252Fpage
Each time the system processes this, it creates another level of nesting, potentially leading to:
- Resource exhaustion - Server wastes CPU parsing deeply nested URLs
- Log pollution - Malformed URLs flood access logs
- SEO damage - Search engines index login pages with redirect loops
- Potential exploits - Could be combined with other vulnerabilities
Real-World Evidence
From production access logs (GPTBot crawling a CakePHP site):
74.7.243.239 - - [20/Nov/2025:13:23:46 +0000] "GET /login?redirect=%2Flogin%3Fredirect%3D%252Flogin%253Fredirect%253D%25252Flogin%25253Fredirect%25253D%2525252Flogin%2525253Fredirect%2525253D%252525252Flogin%252525253Fredirect%252525253D%25252525252Fcommunity%25252525252Fstories..." 200 8802 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.3; +https://openai.com/gptbot)"
This shows 6-7 levels of nested redirects being actively exploited by AI crawlers.
Proposed Solution
Add configurable redirect loop protection to AuthenticationService with opt-in backward compatibility:
Option 1: Configuration-based (Recommended)
// config/app.php or bootstrap
$service->setConfig([
'queryParam' => 'redirect',
'redirectValidation' => [
'enabled' => true, // opt-in for BC
'maxDepth' => 1, // max allowed "redirect=" occurrences
'maxEncodingLevels' => 1, // max allowed %25XX patterns
'maxLength' => 2000, // max URL length
'blockedPatterns' => [ // regex patterns to reject
'#/login#i',
'#/logout#i',
],
],
]);Option 2: Method-based validation
Add a new protected method that can be overridden:
protected function validateRedirect(string $redirect): ?string
{
if (!$this->getConfig('redirectValidation.enabled')) {
return $redirect; // BC: disabled by default
}
// Validation logic here
$maxDepth = $this->getConfig('redirectValidation.maxDepth', 1);
$decodedUrl = urldecode($redirect);
if (substr_count($decodedUrl, 'redirect=') > $maxDepth) {
$this->log('Redirect loop detected: ' . $redirect, 'warning');
return null; // Invalid, fallback to default
}
// More validation...
return $redirect;
}Then call this from getLoginRedirect():
public function getLoginRedirect(ServerRequestInterface $request): ?string
{
$redirect = // ... existing parsing logic ...
return $this->validateRedirect($redirect);
}Validation Checks (suggested)
- Redirect depth check: Count occurrences of
redirect=in decoded URL - Encoding level check: Count occurrences of
%25(percent-encoding of %) - Auth page loop check: Reject redirects to
/login,/logout,/register, etc. - URL length check: Reject excessively long URLs (DOS prevention)
- Pattern blocklist: Allow custom regex patterns to block
Backward Compatibility
- Default: Validation disabled by default to maintain BC
- Opt-in: Users enable via config:
'redirectValidation' => ['enabled' => true] - CakePHP 6+: Consider enabling by default with deprecation notice in 5.x
Benefits
- ✅ Prevents redirect loop attacks
- ✅ Reduces server resource waste
- ✅ Protects against bot abuse
- ✅ Improves security posture
- ✅ Fully backward compatible
- ✅ Configurable and extensible
Alternative: Framework-level middleware
If this doesn't fit the authentication plugin's scope, consider adding it to:
cakephp/cakephpcore as middlewarecakephp/authorizationplugin's redirect handlers
References
- OWASP: Unvalidated Redirects and Forwards
- CWE-601: URL Redirection to Untrusted Site
Implementation offer
I'm happy to submit a PR with tests if this proposal is accepted. Our production implementation (which we can contribute) includes:
SafeAuthenticationServiceextendingAuthenticationServiceSafeRedirectHandlerextending authorization redirect handlers- Comprehensive validation with configurable limits
- Logging of blocked attempts
- Full test coverage
Environment:
- CakePHP: 5.2+
- Authentication plugin: 3.x
- PHP: 8.3+
Let me know if you'd like me to proceed with a PR!