diff --git a/authentik/lib/tests/test_http.py b/authentik/lib/tests/test_http.py index 4fa8ab6196..910993db49 100644 --- a/authentik/lib/tests/test_http.py +++ b/authentik/lib/tests/test_http.py @@ -30,6 +30,11 @@ class TestHTTP(TestCase): request = self.factory.get("/", HTTP_X_FORWARDED_FOR="127.0.0.2") self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.2") + def test_forward_for_invalid(self): + """Test invalid forward for""" + request = self.factory.get("/", HTTP_X_FORWARDED_FOR="foobar") + self.assertEqual(ClientIPMiddleware.get_client_ip(request), ClientIPMiddleware.default_ip) + def test_fake_outpost(self): """Test faked IP which is overridden by an outpost""" token = Token.objects.create( @@ -53,6 +58,17 @@ class TestHTTP(TestCase): }, ) self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") + # Invalid, not a real IP + self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT + self.user.save() + request = self.factory.get( + "/", + **{ + ClientIPMiddleware.outpost_remote_ip_header: "foobar", + ClientIPMiddleware.outpost_token_header: token.key, + }, + ) + self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") # Valid self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT self.user.save() diff --git a/authentik/root/middleware.py b/authentik/root/middleware.py index b66ccee847..05f269e443 100644 --- a/authentik/root/middleware.py +++ b/authentik/root/middleware.py @@ -2,6 +2,7 @@ from collections.abc import Callable from hashlib import sha512 +from ipaddress import ip_address from time import perf_counter, time from typing import Any @@ -174,6 +175,7 @@ class ClientIPMiddleware: def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]): self.get_response = get_response + self.logger = get_logger().bind() def _get_client_ip_from_meta(self, meta: dict[str, Any]) -> str: """Attempt to get the client's IP by checking common HTTP Headers. @@ -185,11 +187,16 @@ class ClientIPMiddleware: "HTTP_X_FORWARDED_FOR", "REMOTE_ADDR", ) - for _header in headers: - if _header in meta: - ips: list[str] = meta.get(_header).split(",") - return ips[0].strip() - return self.default_ip + try: + for _header in headers: + if _header in meta: + ips: list[str] = meta.get(_header).split(",") + # Ensure the IP parses as a valid IP + return str(ip_address(ips[0].strip())) + return self.default_ip + except ValueError as exc: + self.logger.debug("Invalid remote IP", exc=exc) + return self.default_ip # FIXME: this should probably not be in `root` but rather in a middleware in `outposts` # but for now it's fine @@ -226,7 +233,11 @@ class ClientIPMiddleware: Scope.get_isolation_scope().set_user(sentry_user) # Set the outpost service account on the request setattr(request, self.request_attr_outpost_user, user) - return delegated_ip + try: + return str(ip_address(delegated_ip)) + except ValueError as exc: + self.logger.debug("Invalid remote IP from Outpost", exc=exc) + return None def _get_client_ip(self, request: HttpRequest | None) -> str: """Attempt to get the client's IP by checking common HTTP Headers. diff --git a/blueprints/default/flow-default-authentication-flow.yaml b/blueprints/default/flow-default-authentication-flow.yaml index 123c4e5a7a..a7a7e3e16a 100644 --- a/blueprints/default/flow-default-authentication-flow.yaml +++ b/blueprints/default/flow-default-authentication-flow.yaml @@ -82,3 +82,5 @@ entries: order: 10 target: !KeyOf default-authentication-flow-password-binding policy: !KeyOf default-authentication-flow-password-optional + attrs: + failure_result: true diff --git a/website/docs/security/CVE-2024-42490.md b/website/docs/security/CVE-2024-42490.md index 3a024aa80d..f32c98e7f6 100644 --- a/website/docs/security/CVE-2024-42490.md +++ b/website/docs/security/CVE-2024-42490.md @@ -2,7 +2,7 @@ _Reported by [@m2a2](https://github.com/m2a2)_ -## Improper Authorization for Token modification +## Insufficient Authorization for several API endpoints ### Summary diff --git a/website/docs/security/CVE-2024-47070.md b/website/docs/security/CVE-2024-47070.md new file mode 100644 index 0000000000..179f6c62f2 --- /dev/null +++ b/website/docs/security/CVE-2024-47070.md @@ -0,0 +1,35 @@ +# CVE-2024-47070 + +_Reported by [@efpi-bot](https://github.com/efpi-bot) from [LogicalTrust](https://logicaltrust.net/en/)_ + +## Password authentication bypass via X-Forwarded-For HTTP header + +### Summary + +The vulnerability allows bypassing policies by adding X-Forwarded-For header with unparsable IP address, e.g. "a". This results in a possibility to authenticate/authorize to any account with known login or email address. + +Since the default authentication flow uses a policy to enable the password stage only when there is no password stage selected on the Identification stage, this vulnerability can be used to skip this policy and continue without the password stage. + +### Am I affected + +This can be exploited for the following configurations: + +- An attacker can access authentik without a reverse proxy (and `AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS` is not configured properly) +- The reverse proxy configuration does not correctly overwrite X-Forwarded-For +- Policies (User and group bindings do _not_ apply) are bound to authentication/authorization flows + +### Patches + +authentik 2024.6.5 and 2024.8.3 fix this issue. + +### Workarounds + +Ensure the X-Forwarded-For header is always set by the reverse proxy, and is always set to a correct IP. + +In addition you can manually change the _Failure result_ option on policy bindings to _Pass_, which will prevent any stages from being skipped if a malicious request is received. + +### For more information + +If you have any questions or comments about this advisory: + +- Email us at [security@goauthentik.io](mailto:security@goauthentik.io) diff --git a/website/sidebars.js b/website/sidebars.js index 14b46351fd..aa5e755b6b 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -522,6 +522,7 @@ const docsSidebar = { "security/security-hardening", "security/policy", "security/CVE-2024-47077", + "security/CVE-2024-47070", "security/CVE-2024-42490", "security/CVE-2024-38371", "security/CVE-2024-37905",