CVE-2023-46249: Missing Authentication for Critical Function (CWE-306)
value: authentik is an open-source Identity Provider. Prior to versions 2023.8.4 and 2023.10.2, when the default admin user has been deleted, it is potentially possible for an attacker to set the password of the default admin user without any authentication. authentik uses a blueprint to create the default admin user, which can also optionally set the default admin users' password from an environment variable. When the user is deleted, the `initial-setup` flow used to configure authentik after the first installation becomes available again. authentik 2023.8.4 and 2023.10.2 fix this issue. As a workaround, ensure the default admin user (Username `akadmin`) exists and has a password set. It is recommended to use a very strong password for this user, and store it in a secure location like a password manager. It is also possible to deactivate the user to prevent any logins as akadmin.
CWE description: The product does not perform any authentication for functionality that requires a provable user identity or consumes a significant amount of resources.
CVSS v3 base score: 9.8
Published: 2023-10-31T16:15Z
Repository: https://github.com/goauthentik/authentik
Language: Markdown
Files changed: authentik/flows/migrations/0027_auto_20231028_1424.py, blueprints/default/flow-oobe.yaml, blueprints/system/bootstrap.yaml, website/docs/releases/2023/v2023.10.md, website/docs/security/GHSA-rjvp-29xq-f62w.md, website/sidebars.js
Commit date: 2023-10-28 21:24:06 +0200
Commit message: security: fix oobe-flow reuse when akadmin is deleted (#7361)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Diff: diff --git a/authentik/flows/migrations/0027_auto_20231028_1424.py b/authentik/flows/migrations/0027_auto_20231028_1424.py
new file mode 100644
index 000000000..856961a98
--- /dev/null
+++ b/authentik/flows/migrations/0027_auto_20231028_1424.py
@@ -0,0 +1,34 @@
+# Generated by Django 4.2.6 on 2023-10-28 14:24
+
+from django.apps.registry import Apps
+from django.db import migrations
+from django.db.backends.base.schema import BaseDatabaseSchemaEditor
+
+
+def set_oobe_flow_authentication(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
+    from guardian.shortcuts import get_anonymous_user
+
+    Flow = apps.get_model("authentik_flows", "Flow")
+    User = apps.get_model("authentik_core", "User")
+
+    db_alias = schema_editor.connection.alias
+
+    users = User.objects.using(db_alias).exclude(username="akadmin")
+    try:
+        users = users.exclude(pk=get_anonymous_user().pk)
+    # pylint: disable=broad-except
+    except Exception:  # nosec
+        pass
+
+    if users.exists():
+        Flow.objects.filter(slug="initial-setup").update(authentication="require_superuser")
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("authentik_flows", "0026_alter_flow_options"),
+    ]
+
+    operations = [
+        migrations.RunPython(set_oobe_flow_authentication),
+    ]
diff --git a/blueprints/default/flow-oobe.yaml b/blueprints/default/flow-oobe.yaml
index d72f8d652..e37603ebb 100644
--- a/blueprints/default/flow-oobe.yaml
+++ b/blueprints/default/flow-oobe.yaml
@@ -83,10 +83,23 @@ entries:
       return not akadmin.has_usable_password()
   id: policy-default-oobe-password-usable
   identifiers:
     name: default-oobe-password-usable
   model: authentik_policies_expression.expressionpolicy
+- attrs:
+    expression: |
+      # This policy ensures that the setup flow can only be
+      # used one time
+      from authentik.flows.models import Flow, FlowAuthenticationRequirement
+      Flow.objects.filter(slug="initial-setup").update(
+          authentication=FlowAuthenticationRequirement.REQUIRE_SUPERUSER,
+      )
+      return True
+  id: policy-default-oobe-flow-set-authentication
+  identifiers:
+    name: default-oobe-flow-set-authentication
+  model: authentik_policies_expression.expressionpolicy
 - attrs:
     fields:
     - !KeyOf prompt-field-header
     - !KeyOf prompt-field-email
     - !KeyOf prompt-field-password
@@ -127,10 +140,11 @@ entries:
   model: authentik_flows.flowstagebinding
 - attrs:
     evaluate_on_plan: true
     invalid_response_action: retry
     re_evaluate_policies: false
+  id: binding-login
   identifiers:
     order: 100
     stage: !KeyOf stage-default-authentication-login
     target: !KeyOf flow
   model: authentik_flows.flowstagebinding
@@ -142,5 +156,10 @@ entries:
 - identifiers:
     order: 0
     policy: !KeyOf policy-default-oobe-prefill-user
     target: !KeyOf binding-password-write
   model: authentik_policies.policybinding
+- identifiers:
+    order: 0
+    policy: !KeyOf policy-default-oobe-flow-set-authentication
+    target: !KeyOf binding-login
+  model: authentik_policies.policybinding
diff --git a/blueprints/system/bootstrap.yaml b/blueprints/system/bootstrap.yaml
index 5bda8b3ff..07bbd2391 100644
--- a/blueprints/system/bootstrap.yaml
+++ b/blueprints/system/bootstrap.yaml
@@ -40,11 +40,5 @@ entries:
       intent: api
       expiring: false
       user: !KeyOf admin-user
     attrs:
       key: !Context token
-  - model: authentik_blueprints.blueprintinstance
-    identifiers:
-      metadata:
-        labels:
-          blueprints.goauthentik.io/system-bootstrap: "true"
-    state: absent
diff --git a/website/docs/releases/2023/v2023.10.md b/website/docs/releases/2023/v2023.10.md
index cbff117b7..755cd09e3 100644
--- a/website/docs/releases/2023/v2023.10.md
+++ b/website/docs/releases/2023/v2023.10.md
@@ -125,10 +125,11 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2023.10
 
 -   lifecycle: fix otp merge migration (#7315)
 
 ## Fixed in 2023.10.2
 
+-   \*: fix [GHSA-rjvp-29xq-f62w](../security/GHSA-rjvp-29xq-f62w), Reported by [@devSparkle](https://github.com/devSparkle)
 -   blueprints: fix entries with state: absent not being deleted if their serializer has errors (#7345)
 -   crypto: fix race conditions when creating self-signed certificates on startup (#7344)
 -   lifecycle: rework otp_merge migration (#7359)
 -   providers/proxy: to fix duplicate cookie (#7324)
 -   rbac: handle lookup error (#7341)
diff --git a/website/docs/security/GHSA-rjvp-29xq-f62w.md b/website/docs/security/GHSA-rjvp-29xq-f62w.md
new file mode 100644
index 000000000..b4b44d07c
--- /dev/null
+++ b/website/docs/security/GHSA-rjvp-29xq-f62w.md
@@ -0,0 +1,27 @@
+# GHSA-rjvp-29xq-f62w
+
+_Reported by [@devSparkle](https://github.com/devSparkle)_
+
+## Potential Installation takeover when default admin user is deleted
+
+### Summary
+
+In the affected versions, when the default admin user has been deleted, it is potentially possible for an attacker to set the password of the default admin user without any authentication.
+
+### Patches
+
+authentik 2023.8.4 and 2023.10.2 fix this issue, for other versions the workaround can be used.
+
+### Impact
+
+authentik uses a blueprint to create the default admin user, which can also optionally set the default admin users' password from an environment variable. When the user is deleted, the `initial-setup` flow used to configure authentik after the first installation becomes available again.
+
+### Workarounds
+
+Ensure the default admin user (Username `akadmin`) exists and has a password set. It is recommended to use a very strong password for this user, and store it in a secure location like a password manager. It is also possible to deactivate the user to prevent any logins as akadmin.
+
+### 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 e03cd39d9..310eeba17 100644
--- a/website/sidebars.js
+++ b/website/sidebars.js
@@ -405,10 +405,11 @@ const docsSidebar = {
                 title: "Security",
                 slug: "security",
             },
             items: [
                 "security/policy",
+                "security/GHSA-rjvp-29xq-f62w",
                 "security/CVE-2023-39522",
                 "security/CVE-2023-36456",
                 "security/2023-06-cure53",
                 "security/CVE-2023-26481",
                 "security/CVE-2022-23555",

Vulnerable code:   - model: authentik_blueprints.blueprintinstance
    identifiers:
      metadata:
        labels:
          blueprints.goauthentik.io/system-bootstrap: "true"
    state: absent
Fixed code: # Generated by Django 4.2.6 on 2023-10-28 14:24

from django.apps.registry import Apps
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor


def set_oobe_flow_authentication(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
    from guardian.shortcuts import get_anonymous_user

    Flow = apps.get_model("authentik_flows", "Flow")
    User = apps.get_model("authentik_core", "User")

    db_alias = schema_editor.connection.alias

    users = User.objects.using(db_alias).exclude(username="akadmin")
    try:
        users = users.exclude(pk=get_anonymous_user().pk)
    # pylint: disable=broad-except
    except Exception:  # nosec
        pass

    if users.exists():
        Flow.objects.filter(slug="initial-setup").update(authentication="require_superuser")


class Migration(migrations.Migration):
    dependencies = [
        ("authentik_flows", "0026_alter_flow_options"),
    ]

    operations = [
        migrations.RunPython(set_oobe_flow_authentication),
    ]
- attrs:
    expression: |
      # This policy ensures that the setup flow can only be
      # used one time
      from authentik.flows.models import Flow, FlowAuthenticationRequirement
      Flow.objects.filter(slug="initial-setup").update(
          authentication=FlowAuthenticationRequirement.REQUIRE_SUPERUSER,
      )
      return True
  id: policy-default-oobe-flow-set-authentication
  identifiers:
    name: default-oobe-flow-set-authentication
  model: authentik_policies_expression.expressionpolicy
  id: binding-login
- identifiers:
    order: 0
    policy: !KeyOf policy-default-oobe-flow-set-authentication
    target: !KeyOf binding-login
  model: authentik_policies.policybinding
-   \*: fix [GHSA-rjvp-29xq-f62w](../security/GHSA-rjvp-29xq-f62w), Reported by [@devSparkle](https://github.com/devSparkle)
# GHSA-rjvp-29xq-f62w

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

## Potential Installation takeover when default admin user is deleted

### Summary

In the affected versions, when the default admin user has been deleted, it is potentially possible for an attacker to set the password of the default admin user without any authentication.

### Patches

authentik 2023.8.4 and 2023.10.2 fix this issue, for other versions the workaround can be used.

### Impact

authentik uses a blueprint to create the default admin user, which can also optionally set the default admin users' password from an environment variable. When the user is deleted, the `initial-setup` flow used to configure authentik after the first installation becomes available again.

### Workarounds

Ensure the default admin user (Username `akadmin`) exists and has a password set. It is recommended to use a very strong password for this user, and store it in a secure location like a password manager. It is also possible to deactivate the user to prevent any logins as akadmin.

### For more information

If you have any questions or comments about this advisory:

-   Email us at [security@goauthentik.io](mailto:security@goauthentik.io)
                "security/GHSA-rjvp-29xq-f62w",