* providers/oauth2: fix CVE-2024-21637 (#8104) Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update changelog Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Co-authored-by: Jens L <jens@goauthentik.io>
This commit is contained in:
parent
9f3ccfb7c7
commit
00ae97944a
|
@ -85,6 +85,25 @@ class TestAuthorize(OAuthTestCase):
|
||||||
)
|
)
|
||||||
OAuthAuthorizationParams.from_request(request)
|
OAuthAuthorizationParams.from_request(request)
|
||||||
|
|
||||||
|
def test_blocked_redirect_uri(self):
|
||||||
|
"""test missing/invalid redirect URI"""
|
||||||
|
OAuth2Provider.objects.create(
|
||||||
|
name=generate_id(),
|
||||||
|
client_id="test",
|
||||||
|
authorization_flow=create_test_flow(),
|
||||||
|
redirect_uris="data:local.invalid",
|
||||||
|
)
|
||||||
|
with self.assertRaises(RedirectUriError):
|
||||||
|
request = self.factory.get(
|
||||||
|
"/",
|
||||||
|
data={
|
||||||
|
"response_type": "code",
|
||||||
|
"client_id": "test",
|
||||||
|
"redirect_uri": "data:localhost",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
OAuthAuthorizationParams.from_request(request)
|
||||||
|
|
||||||
def test_invalid_redirect_uri_empty(self):
|
def test_invalid_redirect_uri_empty(self):
|
||||||
"""test missing/invalid redirect URI"""
|
"""test missing/invalid redirect URI"""
|
||||||
provider = OAuth2Provider.objects.create(
|
provider = OAuth2Provider.objects.create(
|
||||||
|
|
|
@ -75,6 +75,7 @@ PLAN_CONTEXT_PARAMS = "goauthentik.io/providers/oauth2/params"
|
||||||
SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid"
|
SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid"
|
||||||
|
|
||||||
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}
|
ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}
|
||||||
|
FORBIDDEN_URI_SCHEMES = {"javascript", "data", "vbscript"}
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
|
@ -175,6 +176,10 @@ class OAuthAuthorizationParams:
|
||||||
self.check_scope()
|
self.check_scope()
|
||||||
self.check_nonce()
|
self.check_nonce()
|
||||||
self.check_code_challenge()
|
self.check_code_challenge()
|
||||||
|
if self.request:
|
||||||
|
raise AuthorizeError(
|
||||||
|
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
||||||
|
)
|
||||||
|
|
||||||
def check_redirect_uri(self):
|
def check_redirect_uri(self):
|
||||||
"""Redirect URI validation."""
|
"""Redirect URI validation."""
|
||||||
|
@ -212,10 +217,9 @@ class OAuthAuthorizationParams:
|
||||||
expected=allowed_redirect_urls,
|
expected=allowed_redirect_urls,
|
||||||
)
|
)
|
||||||
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
||||||
if self.request:
|
# Check against forbidden schemes
|
||||||
raise AuthorizeError(
|
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
||||||
self.redirect_uri, "request_not_supported", self.grant_type, self.state
|
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
|
||||||
)
|
|
||||||
|
|
||||||
def check_scope(self):
|
def check_scope(self):
|
||||||
"""Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
|
"""Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
|
||||||
|
|
|
@ -6,6 +6,7 @@ from hashlib import sha256
|
||||||
from re import error as RegexError
|
from re import error as RegexError
|
||||||
from re import fullmatch
|
from re import fullmatch
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -54,6 +55,7 @@ from authentik.providers.oauth2.models import (
|
||||||
RefreshToken,
|
RefreshToken,
|
||||||
)
|
)
|
||||||
from authentik.providers.oauth2.utils import TokenResponse, cors_allow, extract_client_auth
|
from authentik.providers.oauth2.utils import TokenResponse, cors_allow, extract_client_auth
|
||||||
|
from authentik.providers.oauth2.views.authorize import FORBIDDEN_URI_SCHEMES
|
||||||
from authentik.sources.oauth.models import OAuthSource
|
from authentik.sources.oauth.models import OAuthSource
|
||||||
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
|
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
|
||||||
|
|
||||||
|
@ -205,6 +207,10 @@ class TokenParams:
|
||||||
).from_http(request)
|
).from_http(request)
|
||||||
raise TokenError("invalid_client")
|
raise TokenError("invalid_client")
|
||||||
|
|
||||||
|
# Check against forbidden schemes
|
||||||
|
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
|
||||||
|
raise TokenError("invalid_request")
|
||||||
|
|
||||||
self.authorization_code = AuthorizationCode.objects.filter(code=raw_code).first()
|
self.authorization_code = AuthorizationCode.objects.filter(code=raw_code).first()
|
||||||
if not self.authorization_code:
|
if not self.authorization_code:
|
||||||
LOGGER.warning("Code does not exist", code=raw_code)
|
LOGGER.warning("Code does not exist", code=raw_code)
|
||||||
|
|
|
@ -137,6 +137,62 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2023.10
|
||||||
- web/admin: fix @change handler for ak-radio elements (#7348)
|
- web/admin: fix @change handler for ak-radio elements (#7348)
|
||||||
- web/admin: fix role form reacting to enter (#7330)
|
- web/admin: fix role form reacting to enter (#7330)
|
||||||
|
|
||||||
|
## Fixed in 2023.10.3
|
||||||
|
|
||||||
|
- ci: explicitly give write permissions to packages (cherry-pick #7428) (#7430)
|
||||||
|
- core: fix worker beat toggle inverted (cherry-pick #7508) (#7509)
|
||||||
|
- events: fix gdpr compliance always running (cherry-pick #7491) (#7505)
|
||||||
|
- providers/oauth2: set auth_via for token and other endpoints (cherry-pick #7417) (#7427)
|
||||||
|
- providers/proxy: fix closed redis client (cherry-pick #7385) (#7429)
|
||||||
|
- root: Improve multi arch Docker image build speed (cherry-pick #7355) (#7426)
|
||||||
|
- sources/oauth: fix patreon (cherry-pick #7454) (#7456)
|
||||||
|
- stages/email: fix duplicate querystring encoding (cherry-pick #7386) (#7425)
|
||||||
|
- web: bugfix: broken backchannel selector (cherry-pick #7480) (#7507)
|
||||||
|
- web/admin: fix html error on oauth2 provider page (cherry-pick #7384) (#7424)
|
||||||
|
- web/flows: attempt to fix bitwareden android compatibility (cherry-pick #7455) (#7457)
|
||||||
|
|
||||||
|
## Fixed in 2023.10.4
|
||||||
|
|
||||||
|
- ci: fix permissions for release pipeline to publish binaries (cherry-pick #7512) (#7621)
|
||||||
|
- core: bump golang from 1.21.3-bookworm to 1.21.4-bookworm (cherry-pick #7483) (#7622)
|
||||||
|
- events: don't update internal service accounts unless needed (cherry-pick #7611) (#7640)
|
||||||
|
- events: fix missing model\_\* events when not directly authenticated (cherry-pick #7588) (#7597)
|
||||||
|
- events: sanitize functions (cherry-pick #7587) (#7589)
|
||||||
|
- providers/proxy: Fix duplicate cookies when using file system store. (cherry-pick #7541) (#7544)
|
||||||
|
- providers/scim: fix missing schemas attribute for User and Group (cherry-pick #7477) (#7596)
|
||||||
|
- root: specify node and python versions in respective config files, deduplicate in CI (#7620)
|
||||||
|
- security: fix [CVE-2023-48228](../../security/CVE-2023-48228.md), Reported by [@Sapd](https://github.com/Sapd) (#7666)
|
||||||
|
- stages/email: use uuid for email confirmation token instead of username (cherry-pick #7581) (#7584)
|
||||||
|
- web/admin: fix admins not able to delete MFA devices (#7660)
|
||||||
|
|
||||||
|
## Fixed in 2023.10.5
|
||||||
|
|
||||||
|
- blueprints: improve file change handler (cherry-pick #7813) (#7934)
|
||||||
|
- events: add better fallback for sanitize_item to ensure everything can be saved as JSON (cherry-pick #7694) (#7937)
|
||||||
|
- events: fix lint (#7700)
|
||||||
|
- events: include user agent in events (cherry-pick #7693) (#7938)
|
||||||
|
- providers/scim: change familyName default (cherry-pick #7904) (#7930)
|
||||||
|
- root: don't show warning when app has no URLs to import (cherry-pick #7765) (#7935)
|
||||||
|
- root: Fix cache related image build issues (cherry-pick #7831) (#7932)
|
||||||
|
- stages/email: improve error handling for incorrect template syntax (cherry-pick #7758) (#7936)
|
||||||
|
- tests: fix flaky tests (cherry-pick #7676) (#7939)
|
||||||
|
- web: dark/light theme fixes (#7872)
|
||||||
|
- web: fix overflow glitch on ak-page-header (cherry-pick #7883) (#7931)
|
||||||
|
- web/admin: always show oidc well-known URL fields when they're set (#7560)
|
||||||
|
- web/user: fix search not updating app (cherry-pick #7825) (#7933)
|
||||||
|
|
||||||
|
## Fixed in 2023.10.6
|
||||||
|
|
||||||
|
- core: fix PropertyMapping context not being available in request context
|
||||||
|
- outposts: disable deployment and secret reconciler for embedded outpost in code instead of in config (cherry-pick #8021) (#8024)
|
||||||
|
- outposts: fix Outpost reconcile not re-assigning managed attribute (cherry-pick #8014) (#8020)
|
||||||
|
- providers/oauth2: fix [CVE-2024-21637](../../security/CVE-2024-21637.md), Reported by [@lauritzh](https://github.com/lauritzh) (#8104)
|
||||||
|
- providers/oauth2: remember session_id from initial token (cherry-pick #7976) (#7977)
|
||||||
|
- providers/proxy: use access token (cherry-pick #8022) (#8023)
|
||||||
|
- rbac: fix error when looking up permissions for now uninstalled apps (cherry-pick #8068) (#8070)
|
||||||
|
- sources/oauth: fix missing get_user_id for OIDC-like sources (Azure AD) (#7970)
|
||||||
|
- web/flows: fix device picker incorrect foreground color (cherry-pick #8067) (#8069)
|
||||||
|
|
||||||
## API Changes
|
## API Changes
|
||||||
|
|
||||||
#### What's New
|
#### What's New
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
# CVE-2024-21637
|
||||||
|
|
||||||
|
_Reported by [@lauritzh](https://github.com/lauritzh)_
|
||||||
|
|
||||||
|
## XSS in Authentik via JavaScript-URI as Redirect URI and form_post Response Mode
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Given an OAuth2 provider configured with allowed redirect URIs set to `*` or `.*`, an attacker can send an OAuth Authorization request using `response_mode=form_post` and setting `redirect_uri` to a malicious URI, to capture authentik's session token.
|
||||||
|
|
||||||
|
### Patches
|
||||||
|
|
||||||
|
authentik 2023.8.6 and 2023.10.6 fix this issue.
|
||||||
|
|
||||||
|
### Impact
|
||||||
|
|
||||||
|
The impact depends on the attack scenario. In the following I will describe the two scenario that were identified for Authentik.
|
||||||
|
|
||||||
|
#### Redirect URI Misconfiguration
|
||||||
|
|
||||||
|
While advising that this may cause security issues, Authentik generally allows wildcards as Redirect URI. Therefore, using a wildcard-only effectively allowing arbitrary URLS is possible misconfiguration that may be present in real-world instances.
|
||||||
|
|
||||||
|
In such cases, unauthenticated and unprivileged attackers can perform the above described actions.
|
||||||
|
|
||||||
|
### User with (only) App Administration Permissions
|
||||||
|
|
||||||
|
A more likely scenario is an administrative user (e.g. a normal developer) having only permissions to manage applications.
|
||||||
|
|
||||||
|
This relatively user could use the described attacks to perform a privilege escalation.
|
||||||
|
|
||||||
|
### Workaround
|
||||||
|
|
||||||
|
It is recommended to upgrade to the patched version of authentik. If not possible, ensure that OAuth2 providers do not use a wildcard (`*` or `.*`) value as allowed redirect URI setting. (This is _not_ exploitable if part of the redirect URI has a wildcard, for example `https://foo-.*\.bar\.com`)
|
||||||
|
|
||||||
|
### For more information
|
||||||
|
|
||||||
|
If you have any questions or comments about this advisory:
|
||||||
|
|
||||||
|
- Email us at [security@goauthentik.io](mailto:security@goauthentik.io)
|
|
@ -407,6 +407,7 @@ const docsSidebar = {
|
||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
"security/policy",
|
"security/policy",
|
||||||
|
"security/CVE-2024-21637",
|
||||||
"security/CVE-2023-48228",
|
"security/CVE-2023-48228",
|
||||||
"security/GHSA-rjvp-29xq-f62w",
|
"security/GHSA-rjvp-29xq-f62w",
|
||||||
"security/CVE-2023-39522",
|
"security/CVE-2023-39522",
|
||||||
|
|
Reference in New Issue