CVE-2022-4720: URL Redirection to Untrusted Site ('Open Redirect') (CWE-601)
value: Open Redirect in GitHub repository ikus060/rdiffweb prior to 2.5.5.
CWE description: A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks.
CVSS v3 base score: 6.1
Published: 2022-12-27T15:15Z
Repository: https://github.com/ikus060/rdiffweb
Language: HTML
Files changed: rdiffweb/core/notification.py, rdiffweb/core/tests/test_notification.py, rdiffweb/templates/email_access_token_added.html, rdiffweb/templates/email_changed.html, rdiffweb/templates/email_mfa.html, rdiffweb/templates/email_notification.html, rdiffweb/templates/email_password_changed.html, rdiffweb/templates/email_verification_code.html
Commit date: 2022-12-22 16:21:15 -0500
Commit message: Disable automatic hyperlink in email template

Diff: diff --git a/rdiffweb/core/notification.py b/rdiffweb/core/notification.py
index afac05328..503533936 100644
--- a/rdiffweb/core/notification.py
+++ b/rdiffweb/core/notification.py
@@ -71,11 +71,11 @@ class NotificationPlugin(SimplePlugin):
             logger.info("can't sent mail to user [%s] without an email", userobj.username)
             return
 
         # Send a mail notification
         body = self.app.templates.compile_template(
-            "access_token_added.html", **{"header_name": self.app.cfg.header_name, 'user': userobj, 'name': name}
+            "email_access_token_added.html", **{"header_name": self.app.cfg.header_name, 'user': userobj, 'name': name}
         )
         self.bus.publish('queue_mail', to=userobj.email, subject=_("A new access token has been created"), message=body)
 
     def user_attr_changed(self, userobj, attrs={}):
         if not self.send_changed:
@@ -116,11 +116,11 @@ class NotificationPlugin(SimplePlugin):
             logger.info("can't sent mail to user [%s] without an email", userobj.username)
             return
 
         # If the email attributes was changed, send a mail notification.
         body = self.app.templates.compile_template(
-            "password_changed.html", **{"header_name": self.app.cfg.header_name, 'user': userobj}
+            "email_password_changed.html", **{"header_name": self.app.cfg.header_name, 'user': userobj}
         )
         self.bus.publish('queue_mail', to=userobj.email, subject=_("Password changed"), message=body)
 
     def notification_job(self):
         """
diff --git a/rdiffweb/core/tests/test_notification.py b/rdiffweb/core/tests/test_notification.py
index 3d82a503c..ddfae0cf5 100644
--- a/rdiffweb/core/tests/test_notification.py
+++ b/rdiffweb/core/tests/test_notification.py
@@ -62,11 +62,11 @@ class NotificationJobTest(rdiffweb.test.WebCase):
 
         # Then an email is queue for this user
         self.listener.queue_email.assert_called_once_with(
             to='test@test.com',
             subject='Notification',
-            message="<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>\n      You are receiving this email to notify you about your backups. The\n      following repositories are inactive for some time. We invite you to have a look\n      at your last backup schedule.\n    </p>\n    <ul>\n      <li>testcases</li>\n    </ul>\n    <p>\n      If you don't want to be notify about this. You need to review your\n      user preferences.\n    </p>\n  </body>\n</html>",
+            message="<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>\n      You are receiving this email to notify you about your backups. The\n      following repositories are inactive for some time. We invite you to have a look\n      at your last backup schedule.\n    </p>\n    <ul>\n      \n        <li>\n          <a>testcases</a>\n        </li>\n      \n    </ul>\n    <p>If you don't want to be notify about this. You need to review your user preferences.</p>\n  </body>\n</html>",
         )
 
     def test_notification_job_undefined_last_backup_date(self):
         # Given a valid user with a repository configured for notification
         user = UserObject.get_user(self.USERNAME)
@@ -83,11 +83,11 @@ class NotificationJobTest(rdiffweb.test.WebCase):
 
         # Then a notification is sent to the user.
         self.listener.queue_email.assert_called_once_with(
             to='test@test.com',
             subject='Notification',
-            message="<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>\n      You are receiving this email to notify you about your backups. The\n      following repositories are inactive for some time. We invite you to have a look\n      at your last backup schedule.\n    </p>\n    <ul>\n      <li>broker-repo</li>\n    </ul>\n    <p>\n      If you don't want to be notify about this. You need to review your\n      user preferences.\n    </p>\n  </body>\n</html>",
+            message="<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>\n      You are receiving this email to notify you about your backups. The\n      following repositories are inactive for some time. We invite you to have a look\n      at your last backup schedule.\n    </p>\n    <ul>\n      \n        <li>\n          <a>broker-repo</a>\n        </li>\n      \n    </ul>\n    <p>If you don't want to be notify about this. You need to review your user preferences.</p>\n  </body>\n</html>",
         )
 
     def test_notification_job_without_notification(self):
         # Given a valid user with a repository configured without notification (-1)
         user = UserObject.get_user(self.USERNAME)
@@ -133,11 +133,11 @@ class NotificationPluginTest(rdiffweb.test.WebCase):
 
         # Then a email is queue to notify the user.
         self.listener.queue_email.assert_called_once_with(
             to='original_email@test.com',
             subject='Email address changed',
-            message='<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>You recently changed the email address associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
+            message='<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>\n      <a>You recently changed the email address associated with your Rdiffweb account.</a>\n    </p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
         )
 
     def test_email_updated_with_same_value(self):
         # Given a user with an email
         user = UserObject.get_user(self.USERNAME)
@@ -165,11 +165,11 @@ class NotificationPluginTest(rdiffweb.test.WebCase):
 
         # Then a email is send to the user
         self.listener.queue_email.assert_called_once_with(
             to='password_change@test.com',
             subject='Password changed',
-            message='<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>You recently changed the password associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
+            message='<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>You recently changed the password associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
         )
 
     def test_password_change_with_same_value(self):
         # Given a user with a email.
         user = UserObject.get_user(self.USERNAME)
@@ -184,7 +184,7 @@ class NotificationPluginTest(rdiffweb.test.WebCase):
 
         # Then an email is sent to the user
         self.listener.queue_email.assert_called_once_with(
             to='password_change@test.com',
             subject='Password changed',
-            message='<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>You recently changed the password associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
+            message='<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>You recently changed the password associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
         )
diff --git a/rdiffweb/templates/access_token_added.html b/rdiffweb/templates/access_token_added.html
deleted file mode 100644
index 53b6bf5c8..000000000
--- a/rdiffweb/templates/access_token_added.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<html>
-  <head></head>
-  <body>
-    {% trans username=user.username %}Hey {{ username }},{% endtrans %}
-    <p>{% trans %}A new access token, named "{{ name }}", has been created.{% endtrans %}</p>
-    <p>
-      {% trans %}If you did not make this change and believe your account has been compromised, please contact your administrator.{% endtrans %}
-    </p>
-  </body>
-</html>
diff --git a/rdiffweb/templates/email_access_token_added.html b/rdiffweb/templates/email_access_token_added.html
new file mode 100644
index 000000000..91021126c
--- /dev/null
+++ b/rdiffweb/templates/email_access_token_added.html
@@ -0,0 +1,14 @@
+<html>
+  <head></head>
+  <body>
+    <p>
+      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
+    </p>
+    <p>
+      <a>{% trans %}A new access token, named "{{ name }}", has been created.{% endtrans %}</a>
+    </p>
+    <p>
+      {% trans %}If you did not make this change and believe your account has been compromised, please contact your administrator.{% endtrans %}
+    </p>
+  </body>
+</html>
diff --git a/rdiffweb/templates/email_changed.html b/rdiffweb/templates/email_changed.html
index 4293a1a5c..5b40ce14b 100644
--- a/rdiffweb/templates/email_changed.html
+++ b/rdiffweb/templates/email_changed.html
@@ -1,10 +1,14 @@
 <html>
   <head></head>
   <body>
-    {% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}
-    <p>{% trans %}You recently changed the email address associated with your {{ header_name }} account.{% endtrans %}</p>
+    <p>
+      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
+    </p>
+    <p>
+      <a>{% trans %}You recently changed the email address associated with your {{ header_name }} account.{% endtrans %}</a>
+    </p>
     <p>
       {% trans %}If you did not make this change and believe your account has been compromised, please contact your administrator.{% endtrans %}
     </p>
   </body>
 </html>
diff --git a/rdiffweb/templates/email_mfa.html b/rdiffweb/templates/email_mfa.html
index be264bcbb..64be636c9 100644
--- a/rdiffweb/templates/email_mfa.html
+++ b/rdiffweb/templates/email_mfa.html
@@ -1,9 +1,11 @@
 <html>
   <head></head>
   <body>
-    {% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}
+    <p>
+      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
+    </p>
     <p>
       {% if user.mfa %}
         {% trans %}Your {{ header_name }} Account is now protected with Two-Factor Authentication. When you sign in on a new or untrusted device, you'll need your second factor to verify your identity.{% endtrans %}
       {% else %}
         {% trans %}Your {{ header_name }} account is no longer protected with Two-Factor Authentication. You don't need your second factor to sign in.{% endtrans %}
diff --git a/rdiffweb/templates/email_notification.html b/rdiffweb/templates/email_notification.html
index 2ad8270e4..d0dc6d535 100644
--- a/rdiffweb/templates/email_notification.html
+++ b/rdiffweb/templates/email_notification.html
@@ -1,18 +1,21 @@
 <html>
   <head></head>
   <body>
-    {% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}
+    <p>
+      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
+    </p>
     <p>
       {% trans %}You are receiving this email to notify you about your backups. The
       following repositories are inactive for some time. We invite you to have a look
       at your last backup schedule.{% endtrans %}
     </p>
     <ul>
-      {% for r in repos %}<li>{{ r.display_name }}</li>{% endfor %}
+      {% for r in repos %}
+        <li>
+          <a>{{ r.display_name }}</a>
+        </li>
+      {% endfor %}
     </ul>
-    <p>
-      {% trans %}If you don't want to be notify about this. You need to review your
-      user preferences.{% endtrans %}
-    </p>
+    <p>{% trans %}If you don't want to be notify about this. You need to review your user preferences.{% endtrans %}</p>
   </body>
 </html>
diff --git a/rdiffweb/templates/password_changed.html b/rdiffweb/templates/email_password_changed.html
similarity index 73%
rename from rdiffweb/templates/password_changed.html
rename to rdiffweb/templates/email_password_changed.html
index 13bbbbd04..0e3a8f3d9 100644
--- a/rdiffweb/templates/password_changed.html
+++ b/rdiffweb/templates/email_password_changed.html
@@ -1,9 +1,11 @@
 <html>
   <head></head>
   <body>
-    {% trans username=user.username %}Hey {{ username }},{% endtrans %}
+    <p>
+      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
+    </p>
     <p>{% trans %}You recently changed the password associated with your {{ header_name }} account.{% endtrans %}</p>
     <p>
       {% trans %}If you did not make this change and believe your account has been compromised, please contact your administrator.{% endtrans %}
     </p>
   </body>
diff --git a/rdiffweb/templates/email_verification_code.html b/rdiffweb/templates/email_verification_code.html
index da796644b..20db2fe6a 100644
--- a/rdiffweb/templates/email_verification_code.html
+++ b/rdiffweb/templates/email_verification_code.html
@@ -1,9 +1,11 @@
 <html>
   <head></head>
   <body>
-    {% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}
+    <p>
+      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
+    </p>
     <p>
       {% trans %}To help us make sure it's really you, here's the verification code you'll need to log in:{% endtrans %}
     </p>
     <p>
       <strong>{{ code }}</strong>

Vulnerable code:             "access_token_added.html", **{"header_name": self.app.cfg.header_name, 'user': userobj, 'name': name}
            "password_changed.html", **{"header_name": self.app.cfg.header_name, 'user': userobj}
            message="<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>\n      You are receiving this email to notify you about your backups. The\n      following repositories are inactive for some time. We invite you to have a look\n      at your last backup schedule.\n    </p>\n    <ul>\n      <li>testcases</li>\n    </ul>\n    <p>\n      If you don't want to be notify about this. You need to review your\n      user preferences.\n    </p>\n  </body>\n</html>",
            message="<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>\n      You are receiving this email to notify you about your backups. The\n      following repositories are inactive for some time. We invite you to have a look\n      at your last backup schedule.\n    </p>\n    <ul>\n      <li>broker-repo</li>\n    </ul>\n    <p>\n      If you don't want to be notify about this. You need to review your\n      user preferences.\n    </p>\n  </body>\n</html>",
            message='<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>You recently changed the email address associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
            message='<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>You recently changed the password associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
            message='<html>\n  <head></head>\n  <body>\n    Hey admin,\n    <p>You recently changed the password associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
<html>
  <head></head>
  <body>
    {% trans username=user.username %}Hey {{ username }},{% endtrans %}
    <p>{% trans %}A new access token, named "{{ name }}", has been created.{% endtrans %}</p>
    <p>
      {% trans %}If you did not make this change and believe your account has been compromised, please contact your administrator.{% endtrans %}
    </p>
  </body>
</html>
    {% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}
    <p>{% trans %}You recently changed the email address associated with your {{ header_name }} account.{% endtrans %}</p>
    {% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}
    {% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}
      {% for r in repos %}<li>{{ r.display_name }}</li>{% endfor %}
    <p>
      {% trans %}If you don't want to be notify about this. You need to review your
      user preferences.{% endtrans %}
    </p>
    {% trans username=user.username %}Hey {{ username }},{% endtrans %}
    {% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}
Fixed code:             "email_access_token_added.html", **{"header_name": self.app.cfg.header_name, 'user': userobj, 'name': name}
            "email_password_changed.html", **{"header_name": self.app.cfg.header_name, 'user': userobj}
            message="<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>\n      You are receiving this email to notify you about your backups. The\n      following repositories are inactive for some time. We invite you to have a look\n      at your last backup schedule.\n    </p>\n    <ul>\n      \n        <li>\n          <a>testcases</a>\n        </li>\n      \n    </ul>\n    <p>If you don't want to be notify about this. You need to review your user preferences.</p>\n  </body>\n</html>",
            message="<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>\n      You are receiving this email to notify you about your backups. The\n      following repositories are inactive for some time. We invite you to have a look\n      at your last backup schedule.\n    </p>\n    <ul>\n      \n        <li>\n          <a>broker-repo</a>\n        </li>\n      \n    </ul>\n    <p>If you don't want to be notify about this. You need to review your user preferences.</p>\n  </body>\n</html>",
            message='<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>\n      <a>You recently changed the email address associated with your Rdiffweb account.</a>\n    </p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
            message='<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>You recently changed the password associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
            message='<html>\n  <head></head>\n  <body>\n    <p>\n      <a>Hey admin,</a>\n    </p>\n    <p>You recently changed the password associated with your Rdiffweb account.</p>\n    <p>\n      If you did not make this change and believe your account has been compromised, please contact your administrator.\n    </p>\n  </body>\n</html>',
<html>
  <head></head>
  <body>
    <p>
      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
    </p>
    <p>
      <a>{% trans %}A new access token, named "{{ name }}", has been created.{% endtrans %}</a>
    </p>
    <p>
      {% trans %}If you did not make this change and believe your account has been compromised, please contact your administrator.{% endtrans %}
    </p>
  </body>
</html>
    <p>
      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
    </p>
    <p>
      <a>{% trans %}You recently changed the email address associated with your {{ header_name }} account.{% endtrans %}</a>
    </p>
    <p>
      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
    </p>
    <p>
      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
    </p>
      {% for r in repos %}
        <li>
          <a>{{ r.display_name }}</a>
        </li>
      {% endfor %}
    <p>{% trans %}If you don't want to be notify about this. You need to review your user preferences.{% endtrans %}</p>
    <p>
      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
    </p>
    <p>
      <a>{% trans username=(user.fullname or user.username) %}Hey {{ username }},{% endtrans %}</a>
    </p>