Monitor vulnerabilities like this one.
Sign up free to get alerted when software you use is affected.
Kimai allows attackers to redirect users to malicious websites
GHSA-3jp4-mhh4-gcgr
Summary
Kimai's SAML authentication feature doesn't properly check the URL it redirects users to after a successful login. If an attacker can manipulate the SAML login process, they can trick users into visiting a fake or malicious website. To fix this, update your Kimai configuration to only allow trusted URLs for SAML redirects.
What to do
- Update kimai kimai/kimai to version 2.53.0.
Affected software
| Ecosystem | Vendor | Product | Affected versions |
|---|---|---|---|
| Packagist | kimai | kimai/kimai |
< 2.53.0 Fix: upgrade to 2.53.0
|
Original title
Kimai has an Open Redirect via Unvalidated RelayState in SAML ACS Handler
Original description
### Summary
The SAML authentication success handler in Kimai returns the `RelayState` POST parameter as a redirect destination without validating the host or scheme. After a user successfully authenticates via SAML, they are redirected to an attacker-controlled URL if the IdP includes a malicious `RelayState` value. This enables phishing attacks that steal credentials or session tokens post-SSO.
*Requires SAML to be enabled (non-default configuration).*
### Details
Vulnerable file: `src/Saml/Security/SamlAuthenticationSuccessHandler.php`
```php
// Line 27-33
$relayState = $request->request->get('RelayState', $request->query->get('RelayState'));
if (\is_scalar($relayState)) {
$relayState = (string) $relayState;
if ($relayState !== $this->httpUtils->generateUri($request, (string) $this->options['login_path'])) {
return $relayState; // No host/scheme validation — any URL accepted
}
}
```
The only check is that `RelayState` does not equal the configured `login_path`. Any external URL (e.g., `https://attacker.com`) passes this check and is returned as the redirect destination.
The existing unit test `SamlAuthenticationSuccessHandlerTest::testRelayState()` confirms this behavior — an absolute URL in `RelayState` results in a redirect to that URL with no restriction.
### Steps to Reproduce
```
1. Enable SAML authentication in Kimai
2. Configure a SAML IdP (e.g., SimpleSAMLphp)
3. Initiate IdP-initiated SSO with RelayState=https://attacker.com
— or intercept the ACS POST and modify RelayState to https://attacker.com
4. Complete SAML authentication at the IdP
5. Observe: after the SAMLResponse POST to /saml/acs, Kimai issues:
HTTP/1.1 302 Found
Location: https://attacker.com
```
Code-confirmed via unit test (`testRelayState`): `onAuthenticationSuccess` with `RelayState=http://localhost/relayed` redirects directly to that URL. External URLs follow the same code path.
### Impact
While this bug exists it has low practical possibilities and the attacker needs to be able to create a SAML request, meaning either admin access to an IdP supporting such an action OR access to the private SAML keys / certificates.
In other words: only exploitable in IdP-initiated SSO flows where the IdP includes a `RelayState` value supplied by the attacker (e.g., via a malicious link to the IdP).
### Fix
The `RelayState` is validated before redirecting, see #5878
- It may not contain a host or port and cannot start with `//`.
- If it contains a host, it must match the current host.
The SAML authentication success handler in Kimai returns the `RelayState` POST parameter as a redirect destination without validating the host or scheme. After a user successfully authenticates via SAML, they are redirected to an attacker-controlled URL if the IdP includes a malicious `RelayState` value. This enables phishing attacks that steal credentials or session tokens post-SSO.
*Requires SAML to be enabled (non-default configuration).*
### Details
Vulnerable file: `src/Saml/Security/SamlAuthenticationSuccessHandler.php`
```php
// Line 27-33
$relayState = $request->request->get('RelayState', $request->query->get('RelayState'));
if (\is_scalar($relayState)) {
$relayState = (string) $relayState;
if ($relayState !== $this->httpUtils->generateUri($request, (string) $this->options['login_path'])) {
return $relayState; // No host/scheme validation — any URL accepted
}
}
```
The only check is that `RelayState` does not equal the configured `login_path`. Any external URL (e.g., `https://attacker.com`) passes this check and is returned as the redirect destination.
The existing unit test `SamlAuthenticationSuccessHandlerTest::testRelayState()` confirms this behavior — an absolute URL in `RelayState` results in a redirect to that URL with no restriction.
### Steps to Reproduce
```
1. Enable SAML authentication in Kimai
2. Configure a SAML IdP (e.g., SimpleSAMLphp)
3. Initiate IdP-initiated SSO with RelayState=https://attacker.com
— or intercept the ACS POST and modify RelayState to https://attacker.com
4. Complete SAML authentication at the IdP
5. Observe: after the SAMLResponse POST to /saml/acs, Kimai issues:
HTTP/1.1 302 Found
Location: https://attacker.com
```
Code-confirmed via unit test (`testRelayState`): `onAuthenticationSuccess` with `RelayState=http://localhost/relayed` redirects directly to that URL. External URLs follow the same code path.
### Impact
While this bug exists it has low practical possibilities and the attacker needs to be able to create a SAML request, meaning either admin access to an IdP supporting such an action OR access to the private SAML keys / certificates.
In other words: only exploitable in IdP-initiated SSO flows where the IdP includes a `RelayState` value supplied by the attacker (e.g., via a malicious link to the IdP).
### Fix
The `RelayState` is validated before redirecting, see #5878
- It may not contain a host or port and cannot start with `//`.
- If it contains a host, it must match the current host.
Vulnerability type
CWE-601
Open Redirect
Published: 14 Apr 2026 · Updated: 14 Apr 2026 · First seen: 14 Apr 2026