Vulnerability: Canarytokens is an open source tool which helps track activity and actions on your network. A Cross-Site Scripting vulnerability was identified in the history page of triggered Canarytokens. This permits an attacker who recognised an HTTP-based Canarytoken (a URL) to execute Javascript in the Canarytoken's history page (domain: canarytokens.org) when the history page is later visited by the Canarytoken's creator. This vulnerability could be used to disable or delete the affected Canarytoken, or view its activation history. It might also be used as a stepping stone towards revealing more information about the Canarytoken's creator to the attacker. For example, an attacker could recover the email address tied to the Canarytoken, or place Javascript on the history page that redirect the creator towards an attacker-controlled Canarytoken to show the creator's network location. An attacker could only act on the discovered Canarytoken. This issue did not expose other Canarytokens or other Canarytoken creators. The issue has been patched on Canarytokens.org and in the latest release. No signs of successful exploitation of this vulnerability have been found. Users are advised to upgrade. There are no known workarounds for this issue.
Vulnerability ID: CVE-2022-31113
CWE: CWE-79
Severity score: 2.9
Project: https://github.com/thinkst/canarytokens
Published: 2022-07-01
File: templates/history.html
Commit message: Fix XSS reported by Yohann / @2xyo
Commit author: Marco Slaviero

Vulnerable version (before fix):
 <h4 style="text-align: center;">Incident List is Currently Empty</h4>     {% for info in canarydrop['triggered_list'][item]['additional_info'] %}                     <tr class="header_row">                        <td colspan="2">                          {{info}}                        </td>                     </tr>       {%if info == 'iOS-App'%} <h4 style="text-align: center;">Incident List is Currently Empty</h4>                           <td>                             {{ canarydrop['triggered_list'][item]['additional_info'][info][info_item][0] == '1'                                   if info_item in ['enabled','installed']                                   else canarydrop['triggered_list'][item]['additional_info'][info][info_item]|join(', ') }}                           </td>                         </tr>       {% endfor %}

Fixed version (after fix):
 <h4 style="text-align: center;">Incident List is Currently Empty</h4>     {% for info in canarydrop['triggered_list'][item]['additional_info'] %}                     <tr class="header_row">                        <td colspan="2">                          {{info|e}}                        </td>                     </tr>       {%if info == 'iOS-App'%} <h4 style="text-align: center;">Incident List is Currently Empty</h4>                           <td>                             {{ canarydrop['triggered_list'][item]['additional_info'][info][info_item][0] == '1'                                   if info_item in ['enabled','installed']                                   else canarydrop['triggered_list'][item]['additional_info'][info][info_item]|join(', ')|e }}                           </td>                         </tr>       {% endfor %}

Patch:
patch: @@ -306,7 +306,7 @@ <h4 style="text-align: center;">Incident List is Currently Empty</h4>
     {% for info in canarydrop['triggered_list'][item]['additional_info'] %}
                     <tr class="header_row">
                        <td colspan="2">
-                         {{info}}
+                         {{info|e}}
                        </td>
                     </tr>
       {%if info == 'iOS-App'%}
@@ -353,7 +353,7 @@ <h4 style="text-align: center;">Incident List is Currently Empty</h4>
                           <td>
                             {{ canarydrop['triggered_list'][item]['additional_info'][info][info_item][0] == '1'
                                   if info_item in ['enabled','installed']
-                                  else canarydrop['triggered_list'][item]['additional_info'][info][info_item]|join(', ') }}
+                                  else canarydrop['triggered_list'][item]['additional_info'][info][info_item]|join(', ')|e }}
                           </td>
                         </tr>
       {% endfor %}
path: templates/history.html