Skip to content

Commit

Permalink
security: fix CVE-2024-42490 (cherry-pick #11022) (#11025)
Browse files Browse the repository at this point in the history
security: fix CVE-2024-42490 (#11022)

CVE-2024-42490

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
  • Loading branch information
gcp-cherry-pick-bot[bot] and BeryJu authored Aug 22, 2024
1 parent b727656 commit 359b343
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 5 deletions.
3 changes: 2 additions & 1 deletion authentik/core/api/used_by.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from rest_framework.response import Response

from authentik.core.api.utils import PassiveSerializer
from authentik.rbac.filters import ObjectFilter


class DeleteAction(Enum):
Expand Down Expand Up @@ -53,7 +54,7 @@ class UsedByMixin:
@extend_schema(
responses={200: UsedBySerializer(many=True)},
)
@action(detail=True, pagination_class=None, filter_backends=[])
@action(detail=True, pagination_class=None, filter_backends=[ObjectFilter])
def used_by(self, request: Request, *args, **kwargs) -> Response:
"""Get a list of all objects that use this object"""
model: Model = self.get_object()
Expand Down
5 changes: 3 additions & 2 deletions authentik/crypto/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event, EventAction
from authentik.rbac.decorators import permission_required
from authentik.rbac.filters import ObjectFilter

LOGGER = get_logger()

Expand Down Expand Up @@ -265,7 +266,7 @@ def generate(self, request: Request) -> Response:
],
responses={200: CertificateDataSerializer(many=False)},
)
@action(detail=True, pagination_class=None, filter_backends=[])
@action(detail=True, pagination_class=None, filter_backends=[ObjectFilter])
def view_certificate(self, request: Request, pk: str) -> Response:
"""Return certificate-key pairs certificate and log access"""
certificate: CertificateKeyPair = self.get_object()
Expand Down Expand Up @@ -295,7 +296,7 @@ def view_certificate(self, request: Request, pk: str) -> Response:
],
responses={200: CertificateDataSerializer(many=False)},
)
@action(detail=True, pagination_class=None, filter_backends=[])
@action(detail=True, pagination_class=None, filter_backends=[ObjectFilter])
def view_private_key(self, request: Request, pk: str) -> Response:
"""Return certificate-key pairs private key and log access"""
certificate: CertificateKeyPair = self.get_object()
Expand Down
60 changes: 60 additions & 0 deletions authentik/crypto/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,46 @@ def test_private_key_download(self):
self.assertEqual(200, response.status_code)
self.assertIn("Content-Disposition", response)

def test_certificate_download_denied(self):
"""Test certificate export (download)"""
self.client.logout()
keypair = create_test_cert()
response = self.client.get(
reverse(
"authentik_api:certificatekeypair-view-certificate",
kwargs={"pk": keypair.pk},
)
)
self.assertEqual(403, response.status_code)
response = self.client.get(
reverse(
"authentik_api:certificatekeypair-view-certificate",
kwargs={"pk": keypair.pk},
),
data={"download": True},
)
self.assertEqual(403, response.status_code)

def test_private_key_download_denied(self):
"""Test private_key export (download)"""
self.client.logout()
keypair = create_test_cert()
response = self.client.get(
reverse(
"authentik_api:certificatekeypair-view-private-key",
kwargs={"pk": keypair.pk},
)
)
self.assertEqual(403, response.status_code)
response = self.client.get(
reverse(
"authentik_api:certificatekeypair-view-private-key",
kwargs={"pk": keypair.pk},
),
data={"download": True},
)
self.assertEqual(403, response.status_code)

def test_used_by(self):
"""Test used_by endpoint"""
self.client.force_login(create_test_admin_user())
Expand Down Expand Up @@ -246,6 +286,26 @@ def test_used_by(self):
],
)

def test_used_by_denied(self):
"""Test used_by endpoint"""
self.client.logout()
keypair = create_test_cert()
OAuth2Provider.objects.create(
name=generate_id(),
client_id="test",
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://localhost",
signing_key=keypair,
)
response = self.client.get(
reverse(
"authentik_api:certificatekeypair-used-by",
kwargs={"pk": keypair.pk},
)
)
self.assertEqual(403, response.status_code)

def test_discovery(self):
"""Test certificate discovery"""
name = generate_id()
Expand Down
3 changes: 2 additions & 1 deletion authentik/flows/api/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
)
from authentik.lib.views import bad_request_message
from authentik.rbac.decorators import permission_required
from authentik.rbac.filters import ObjectFilter

LOGGER = get_logger()

Expand Down Expand Up @@ -281,7 +282,7 @@ def set_background_url(self, request: Request, slug: str):
400: OpenApiResponse(description="Flow not applicable"),
},
)
@action(detail=True, pagination_class=None, filter_backends=[])
@action(detail=True, pagination_class=None, filter_backends=[ObjectFilter])
def execute(self, request: Request, slug: str):
"""Execute flow for current user"""
# Because we pre-plan the flow here, and not in the planner, we need to manually clear
Expand Down
3 changes: 2 additions & 1 deletion authentik/outposts/api/service_connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
KubernetesServiceConnection,
OutpostServiceConnection,
)
from authentik.rbac.filters import ObjectFilter


class ServiceConnectionSerializer(ModelSerializer, MetaNameSerializer):
Expand Down Expand Up @@ -75,7 +76,7 @@ class ServiceConnectionViewSet(
filterset_fields = ["name"]

@extend_schema(responses={200: ServiceConnectionStateSerializer(many=False)})
@action(detail=True, pagination_class=None, filter_backends=[])
@action(detail=True, pagination_class=None, filter_backends=[ObjectFilter])
def state(self, request: Request, pk: str) -> Response:
"""Get the service connection's state"""
connection = self.get_object()
Expand Down
31 changes: 31 additions & 0 deletions website/docs/security/CVE-2024-42490.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# CVE-2024-42490

_Reported by [@m2a2](https://github.com/m2a2)_

## Improper Authorization for Token modification

### Summary

Several API endpoints can be accessed by users without correct authentication/authorization.

The main API endpoints affected by this:

- `/api/v3/crypto/certificatekeypairs/<uuid>/view_certificate/`
- `/api/v3/crypto/certificatekeypairs/<uuid>/view_private_key/`
- `/api/v3/.../used_by/`

Note that all of the affected API endpoints require the knowledge of the ID of an object, which especially for certificates is not accessible to an unprivileged user. Additionally the IDs for most objects are UUIDv4, meaning they are not easily guessable/enumerable.

### Patches

authentik 2024.4.4, 2024.6.4 and 2024.8.0 fix this issue.

### Workarounds

Access to the API endpoints can be blocked at a Reverse-proxy/Load balancer level to prevent this issue from being exploited.

### For more information

If you have any questions or comments about this advisory:

- Email us at [security@goauthentik.io](mailto:security@goauthentik.io)
1 change: 1 addition & 0 deletions website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ const docsSidebar = {
items: [
"security/security-hardening",
"security/policy",
"security/CVE-2024-42490",
"security/CVE-2024-38371",
"security/CVE-2024-37905",
"security/CVE-2024-23647",
Expand Down

0 comments on commit 359b343

Please sign in to comment.