CVE-2023-25171 (published 2023-02-15T15:15Z)

Kiwi TCMS, an open source test management system, does not impose rate limits in versions prior to 12.0. This makes it easier to attempt denial-of-service attacks against the Password reset page. An attacker could potentially send a large number of emails if they know the email addresses of users in Kiwi TCMS. Additionally that may strain SMTP resources. Users should upgrade to v12.0 or later to receive a patch. As potential workarounds, users may install and configure a rate-limiting proxy in front of Kiwi TCMS and/or configure rate limits on their email server when possible.

CVSS v3 base score: 5.9, MEDIUM (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-770
cwe_name: Allocation of Resources Without Limits or Throttling
description: The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.
extended_description: Code frequently has to work with limited resources, so programmers must be careful to ensure that resources are not consumed too quickly, or too easily.  Without use of quotas, resource limits, or other protection mechanisms, it can be easy for an attacker to consume many resources by rapidly making many requests, or causing larger resources to be used than is needed. When too many resources are allocated, or if a single resource is too large, then it can prevent the code from working correctly, possibly leading to a denial of service.
         

Fix information:
repo_url: https://github.com/kiwitcms/Kiwi
commit_details: repo_url: https://github.com/kiwitcms/Kiwi
author: Alexander Todorov
author_date: 2023-02-09 16:35:52+02:00
msg: Show captcha on password reset form if enabled
repository: repo_url: https://github.com/kiwitcms/Kiwi
repo_name: kiwitcms/Kiwi
description: open source test management system with over 2 million downloads!
repo_language: Python
owner: kiwitcms
file_changes: filename: forms.py
change_type: ModificationType.MODIFY
diff: @@ -94,6 +94,14 @@ class PasswordResetForm(
     kiwitcms-tenants is installed.
     """
 
+    captcha = (
+        fields.CaptchaField(
+            widget=CustomCaptchaTextInput(attrs={"class": "form-control"})
+        )
+        if settings.USE_CAPTCHA
+        else None
+    )
+
     def save(  # pylint: disable=too-many-arguments
         self,
         domain_override=None,

programming_language: Python
filename: test_views.py
change_type: ModificationType.MODIFY
diff: @@ -400,8 +400,25 @@ class TestPasswordResetView(TestCase):
         user = User.objects.create_user("kiwi-tester", "tester@example.com", "password")
         user.is_active = True
         user.save()
-        data = {"email": "tester@example.com"}
-        response = self.client.post(self.password_reset_url, data, follow=True)
+
+        try:
+            # https://github.com/mbi/django-simple-captcha/issues/84
+            # pylint: disable=import-outside-toplevel
+            from captcha.conf import settings as captcha_settings
+
+            captcha_settings.CAPTCHA_TEST_MODE = True
+
+            response = self.client.post(
+                self.password_reset_url,
+                {
+                    "email": "tester@example.com",
+                    "captcha_0": "PASSED",
+                    "captcha_1": "PASSED",
+                },
+                follow=True,
+            )
+        finally:
+            captcha_settings.CAPTCHA_TEST_MODE = False
 
         self.assertContains(response, _("Password reset email was sent"))
 

programming_language: Python
filename: password_reset_form.html
change_type: ModificationType.MODIFY
diff: @@ -18,6 +18,10 @@
             <input type="text" class="form-control" id="inputEmail" name="email" placeholder="" tabindex="1">
           </div>
         </div>
+        {% if 'captcha' in form.fields %}
+            {{ form.captcha.errors }}
+            {{ form.captcha }}
+        {% endif %}
         <div class="form-group">
           <div class="col-xs-12 col-sm-offset-2 col-sm-10 col-md-offset-2 col-md-10 submit">
             <button type="submit" class="btn btn-primary btn-lg" tabindex="4">{% trans "Password reset" %}</button>

programming_language: HTML