VYPR
Critical severityNVD Advisory· Published Aug 22, 2024· Updated Aug 22, 2024

authentik has Insufficient Authorization for several API endpoints

CVE-2024-42490

Description

authentik is an open-source Identity Provider. Several API endpoints can be accessed by users without correct authentication/authorization. The main API endpoints affected by this are /api/v3/crypto/certificatekeypairs//view_certificate/, /api/v3/crypto/certificatekeypairs//view_private_key/, and /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. authentik 2024.4.4, 2024.6.4 and 2024.8.0 fix this issue.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

authentik suffers from improper authorization on API endpoints, allowing unauthenticated access to certificate keys and object relationships if the object ID is known.

authentik, an open-source Identity Provider, has a vulnerability in several API endpoints that lack proper authentication and authorization checks [1]. The affected endpoints include /api/v3/crypto/certificatekeypairs//view_certificate/, /api/v3/crypto/certificatekeypairs//view_private_key/, and /api/v3/.../used_by/. The root cause is that the endpoints do not verify whether the requesting user has the necessary permissions to access the requested objects [2] [3].

Exploitation requires knowledge of the object's UUID, which is typically a UUIDv4 and not easily guessable. However, an attacker who obtains a valid UUID through information leakage or other means can access these endpoints without authentication. The attack is network-based and does not require any privileges [1].

If exploited, an attacker can view certificate details, download private keys, and inspect the relationships (used_by) of objects, potentially leading to further compromise of the identity provider and its associated services [1].

The vulnerability is fixed in authentik versions 2024.4.4, 2024.6.4, and 2024.8.0. Users are advised to upgrade to these versions or later [1] [2] [3].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
goauthentik.ioGo
>= 2024.6.0-rc1, < 2024.6.42024.6.4
goauthentik.ioGo
< 2024.4.42024.4.4

Affected products

3

Patches

2
359b343f5152

security: fix CVE-2024-42490 (cherry-pick #11022) (#11025)

https://github.com/goauthentik/authentikgcp-cherry-pick-bot[bot]Aug 22, 2024via ghsa
7 files changed · +101 5
  • authentik/core/api/used_by.py+2 1 modified
    @@ -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):
    @@ -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()
    
  • authentik/crypto/api.py+3 2 modified
    @@ -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()
     
    @@ -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()
    @@ -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()
    
  • authentik/crypto/tests.py+60 0 modified
    @@ -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())
    @@ -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()
    
  • authentik/flows/api/flows.py+2 1 modified
    @@ -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()
     
    @@ -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
    
  • authentik/outposts/api/service_connections.py+2 1 modified
    @@ -26,6 +26,7 @@
         KubernetesServiceConnection,
         OutpostServiceConnection,
     )
    +from authentik.rbac.filters import ObjectFilter
     
     
     class ServiceConnectionSerializer(ModelSerializer, MetaNameSerializer):
    @@ -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()
    
  • website/docs/security/CVE-2024-42490.md+31 0 added
    @@ -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)
    
  • website/sidebars.js+1 0 modified
    @@ -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",
    
19318d4c00bb

security: fix CVE-2024-42490 (cherry-pick #11022) (#11024)

https://github.com/goauthentik/authentikgcp-cherry-pick-bot[bot]Aug 22, 2024via ghsa
7 files changed · +101 5
  • authentik/core/api/used_by.py+2 1 modified
    @@ -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):
    @@ -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()
    
  • authentik/crypto/api.py+3 2 modified
    @@ -36,6 +36,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()
     
    @@ -266,7 +267,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()
    @@ -296,7 +297,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()
    
  • authentik/crypto/tests.py+60 0 modified
    @@ -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())
    @@ -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()
    
  • authentik/flows/api/flows.py+2 1 modified
    @@ -33,6 +33,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()
     
    @@ -277,7 +278,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
    
  • authentik/outposts/api/service_connections.py+2 1 modified
    @@ -23,6 +23,7 @@
         KubernetesServiceConnection,
         OutpostServiceConnection,
     )
    +from authentik.rbac.filters import ObjectFilter
     
     
     class ServiceConnectionSerializer(ModelSerializer, MetaNameSerializer):
    @@ -88,7 +89,7 @@ def types(self, request: Request) -> Response:
             return Response(TypeCreateSerializer(data, many=True).data)
     
         @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()
    
  • website/docs/security/CVE-2024-42490.md+31 0 added
    @@ -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)
    
  • website/sidebars.js+1 0 modified
    @@ -436,6 +436,7 @@ const docsSidebar = {
                 },
                 items: [
                     "security/policy",
    +                "security/CVE-2024-42490",
                     "security/CVE-2024-38371",
                     "security/CVE-2024-37905",
                     "security/CVE-2024-23647",
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.