VYPR
Moderate severityNVD Advisory· Published Dec 8, 2020· Updated Aug 4, 2024

Remote Code Execution (RCE) Exploit on Cross Site Scripting (XSS) Vulnerability

CVE-2020-26249

Description

Red Discord Bot Dashboard is an easy-to-use interactive web dashboard to control your Redbot. In Red Discord Bot before version 0.1.7a an RCE exploit has been discovered. This exploit allows Discord users with specially crafted Server names and Usernames/Nicknames to inject code into the webserver front-end code. By abusing this exploit, it's possible to perform destructive actions and/or access sensitive information. This high severity exploit has been fixed on version 0.1.7a. There are no workarounds, bot owners must upgrade their relevant packages (Dashboard module and Dashboard webserver) in order to patch this issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
red-dashboardPyPI
< 0.1.7a0.1.7a

Affected products

1

Patches

2
a6b978533800

[UI] Fix SelectPicker not rendering properly

https://github.com/Cog-Creators/Red-DashboardNeuroAssassinDec 1, 2020via ghsa
1 file changed · +41 16
  • reddash/app/home/templates/guild.html+41 16 modified
    @@ -930,20 +930,20 @@ <h5>{{ data['message'] }}</h5>
                 img.attr("src", `${img.attr("data-src-url")}png`)
    
             }
    
         }
    
    +
    
    +    function safe(str) {
    
    +        return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
    
    +    }
    
     </script>
    
     
    
     {% if data['status'] == 1 and data['data']['status'] == 1 %}
    
     
    
    -{% if 'aliascc' in data['data']['permslist'] %}
    
    +{% if 'aliascc' in data['data']['permslist'] and false%}
    
     <script>
    
         /* ---------------------------------------------------------------------------------------------------------------------
    
                                                             Aliases group
    
            --------------------------------------------------------------------------------------------------------------------- */
    
     
    
    -    function safe(str) {
    
    -        return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
    
    -    }
    
    -
    
         // Alias modal
    
         $(document).on('click', '.editaliasbutton', function () {
    
             var command = $(this).parent().parent().data("command")
    
    @@ -1186,28 +1186,35 @@ <h5>{{ data['message'] }}</h5>
                 } else if (json.status === 1 && json.data.status === 0) {
    
                     $("#targetstatus").html(`{{ _('Failed to fetch targets') }}: ${json.data.message}`)
    
                 } else {
    
    +                let big_ol_dict = {}
    
                     select.html("")
    
     
    
                     var chopt = [`<optgroup label="{{ _('Channels') }}">`]
    
                     for (let [id, name] of json.data.CHANNELS) {
    
    -                    chopt.push(`<option value=${id}>${name}</option>`)
    
    +                    chopt.push(`<option value=${id} class="selectpicker-element-${id}">Loading...</option>`)
    
    +                    big_ol_dict[id] = name
    
                     }
    
                     chopt.push("</optgroup>")
    
                     select.append(chopt.join(""))
    
     
    
                     var ropt = [`<optgroup label="{{ _('Roles') }}">`]
    
                     for (let [id, name] of json.data.ROLES) {
    
    -                    ropt.push(`<option value=${id}>${name}</option>`)
    
    +                    ropt.push(`<option value=${id} class="selectpicker-element-${id}">Loading...</option>`)
    
    +                    big_ol_dict[id] = name
    
                     }
    
                     ropt.push("</optgroup>")
    
                     select.append(ropt.join(""))
    
     
    
                     var uopt = [`<optgroup label="{{ _('Users') }}">`]
    
                     for (let [id, name] of json.data.USERS) {
    
    -                    uopt.push(`<option value=${id}>${name}</option>`)
    
    +                    uopt.push(`<option value=${id} class="selectpicker-element-${id}">Loading...</option>`)
    
    +                    big_ol_dict[id] = name
    
                     }
    
                     uopt.push("</optgroup>")
    
                     select.append(uopt.join(""))
    
    +                for (let [id, name] of Object.entries(big_ol_dict)) {
    
    +                    $(`.selectpicker-element-${id}`).text(name)
    
    +                }
    
                 }
    
                 select.selectpicker({ title: "{{ _('Choose target') }}" })
    
                 select.removeAttr("disabled")
    
    @@ -1299,18 +1306,24 @@ <h5>{{ data['message'] }}</h5>
                     $("#rulesdiv").html("")
    
                     var overall = ['<h3 style="margin-bottom: 10px">{{ _("Cog rules") }}</h3>']
    
                     var allcoglines = ["<ul>"]
    
    +
    
    +                let big_ol_dict_two = {}
    
    +                let cog_counter = 0
    
    +
    
                     for (let [cog, rules] of Object.entries(json.data.COG)) {
    
                         var coglines = []
    
                         for (let rule of rules) {
    
                             if (rule.type === "Default") {
    
                                 coglines.unshift(`<li>{{ _('By default, users are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cog}</code> {{ _('cog') }}.</li>`)
    
                             } else if (rule.type === "Role") {
    
    -                            coglines.push(`<li>{{ _('Users with the') }} <code>${rule.name}</code> {{ _('role') }} (${rule.id}) {{ _('are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cog}</code> {{ _('cog') }}.</li>`)
    
    +                            coglines.push(`<li>{{ _('Users with the') }} <code id="cog-rules-${cog_counter}">Loading...</code> {{ _('role') }} (${rule.id}) {{ _('are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cog}</code> {{ _('cog') }}.</li>`)
    
                             } else if (rule.type === "Channel") {
    
    -                            coglines.push(`<li>{{ _('Users in the') }} <code>${rule.name}</code> {{ _('channel') }} (${rule.id}) {{ _('are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cog}</code> {{ _('cog') }}.</li>`)
    
    +                            coglines.push(`<li>{{ _('Users in the') }} <code id="cog-rules-${cog_counter}">Loading...</code> {{ _('channel') }} (${rule.id}) {{ _('are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cog}</code> {{ _('cog') }}.</li>`)
    
                             } else {
    
    -                            coglines.push(`<li>{{ _('User') }} <code>${rule.name}</code> (${rule.id}) {{ _('is') }} ${rule.permission} {{ _('permission to use the') }} <code>${cog}</code> {{ _('cog') }}.</li>`)
    
    +                            coglines.push(`<li>{{ _('User') }} <code id="cog-rules-${cog_counter}">Loading...</code> (${rule.id}) {{ _('is') }} ${rule.permission} {{ _('permission to use the') }} <code>${cog}</code> {{ _('cog') }}.</li>`)
    
                             }
    
    +                        big_ol_dict_two[`cog-rules-${cog_counter}`] = rule.name
    
    +                        cog_counter += 1
    
                         }
    
                         if (coglines) {
    
                             allcoglines = allcoglines.concat(coglines)
    
    @@ -1324,18 +1337,23 @@ <h5>{{ data['message'] }}</h5>
     
    
                     overall.push('<h3 style="margin-bottom: 10px">{{ _("Command rules") }}</h3>')
    
                     var allcmdlines = ["<ul>"]
    
    +
    
    +                let cmd_counter = 0
    
    +
    
                     for (let [cmd, rules] of Object.entries(json.data.COMMAND)) {
    
                         var cmdlines = []
    
                         for (let rule of rules) {
    
                             if (rule.type === "Default") {
    
                                 cmdlines.unshift(`<li>{{ _('By default, users are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cmd}</code> {{ _('command') }}.</li>`)
    
                             } else if (rule.type === "Role") {
    
    -                            cmdlines.push(`<li>{{ _('Users with the') }} <code>${rule.name}</code> {{ _('role') }} (${rule.id}) {{ _('are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cmd}</code> {{ _('command') }}.</li>`)
    
    +                            cmdlines.push(`<li>{{ _('Users with the') }} <code id="cmd-rules-${cmd_counter}">Loading...</code> {{ _('role') }} (${rule.id}) {{ _('are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cmd}</code> {{ _('command') }}.</li>`)
    
                             } else if (rule.type === "Channel") {
    
    -                            cmdlines.push(`<li>{{ _('Users in the') }} <code>${rule.name}</code> {{ _('channel') }} (${rule.id}) {{ _('are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cmd}</code> {{ _('command') }}.</li>`)
    
    +                            cmdlines.push(`<li>{{ _('Users in the') }} <code id="cmd-rules-${cmd_counter}">Loading...</code> {{ _('channel') }} (${rule.id}) {{ _('are') }} ${rule.permission} {{ _('permission to use the') }} <code>${cmd}</code> {{ _('command') }}.</li>`)
    
                             } else {
    
    -                            cmdlines.push(`<li>{{ _('User') }} <code>${rule.name}</code> (${rule.id}) {{ _('is') }} ${rule.permission} {{ _('permission to use the') }} <code>${cmd}</code> {{ _('command') }}.</li>`)
    
    +                            cmdlines.push(`<li>{{ _('User') }} <code id="cmd-rules-${cmd_counter}">Loading...</code> (${rule.id}) {{ _('is') }} ${rule.permission} {{ _('permission to use the') }} <code>${cmd}</code> {{ _('command') }}.</li>`)
    
                             }
    
    +                        big_ol_dict_two[`cmd-rules-${cmd_counter}`] = rule.name
    
    +                        cmd_counter += 1
    
                         }
    
                         if (cmdlines) {
    
                             allcmdlines = allcmdlines.concat(cmdlines)
    
    @@ -1347,6 +1365,9 @@ <h5>{{ data['message'] }}</h5>
                     }
    
                     overall = overall.concat(allcmdlines)
    
                     $("#rulesdiv").html(overall.join(""))
    
    +                for (let [id, name] of Object.entries(big_ol_dict_two)) {
    
    +                    $(`#${id}`).text(name)
    
    +                }
    
                     $("#fetchrulesstatus").html("{{ _('Refreshed rules') }}.")
    
                 }
    
             }
    
    @@ -1378,18 +1399,20 @@ <h5>{{ data['message'] }}</h5>
     
    
         $(document).on('click', '.adminroleoption', function () {
    
             var elm = $(this)
    
    +        let random_number = Math.floor(Math.random() * Math.floor(100000))
    
             $("#adminrolelist").append(`
    
                     <li>
    
                         <div class="row">
    
                             <div class="col-md-10 col-8">
    
    -                            <input class="form-control adminroleinput" value="${elm.text()}" disabled=True data-id="${elm.attr("data-id")}">
    
    +                            <input class="form-control adminroleinput" value="Loading..." disabled=True data-id="${elm.attr("data-id")}" id="admin-role-${random_number}">
    
                             </div>
    
                             <div class="col-md-1 col-1">
    
                                 <span class="admin-role-x clickable"><i class="tim-icons icon-simple-remove" style="float: right; margin-top: 10px;"></i></span>
    
                             </div>
    
                         </div>
    
                     </li>
    
                 `)
    
    +        $(`#admin-role-${random_number}`).val(elm.text())
    
             elm.remove()
    
         })
    
     
    
    @@ -1442,18 +1465,20 @@ <h5>{{ data['message'] }}</h5>
     
    
         $(document).on('click', '.modroleoption', function () {
    
             var elm = $(this)
    
    +        let random_number = Math.floor(Math.random() * Math.floor(100000))
    
             $("#modrolelist").append(`
    
                     <li>
    
                         <div class="row">
    
                             <div class="col-md-10 col-8">
    
    -                            <input class="form-control modroleinput" value="${elm.text()}" disabled=True data-id="${elm.attr("data-id")}">
    
    +                            <input class="form-control modroleinput" value="Loading..." disabled=True data-id="${elm.attr("data-id")}" id="mod-role-${random_number}">
    
                             </div>
    
                             <div class="col-md-1 col-1">
    
                                 <span class="mod-role-x clickable"><i class="tim-icons icon-simple-remove" style="float: right; margin-top: 10px;"></i></span>
    
                             </div>
    
                         </div>
    
                     </li>
    
                 `)
    
    +        $(`#mod-role-${random_number}`).val(elm.text())
    
             elm.remove()
    
         })
    
     
    
    
99d88b840674

Fix unformatted HTML

https://github.com/Cog-Creators/Red-DashboardNeuroAssassinNov 30, 2020via ghsa
1 file changed · +6 2
  • reddash/app/home/templates/dashboard.html+6 2 modified
    @@ -72,6 +72,7 @@ <h1>{{ _('Loading servers...') }}</h1>
                     } else {
    
                         var base_guild_url = "{{ url_for('home_blueprint.guild', guild='123456789123456789') }}"
    
                         $("#serverrow").html("")
    
    +                    let counter = 0
    
                         for (let g of json.data) {
    
                             var current_guild_url = base_guild_url.replace("123456789123456789", g.id)
    
                             $("#serverrow").append(`
    
    @@ -80,13 +81,16 @@ <h1>{{ _('Loading servers...') }}</h1>
                                         <div class="card h-100" onmouseover="playGif(this)" onmouseout="stopGif(this)">
    
                                             <img class="card-img-top" src="${g.icon}png" alt="Card image cap" data-src-url="${g.icon}" data-is-animated=${g.animated}>
    
                                             <div class="card-body">
    
    -                                            <h5 class="card-title">${g.name}</h5>
    
    -                                            <p class="card-text">Owner: ${g.owner}</p>
    
    +                                            <h5 class="card-title" id="guild-counter-${counter}">Loading...</h5>
    
    +                                            <p class="card-text" id="owner-counter-${counter}">Owner: Loading...</p>
    
                                             </div>
    
                                         </div>
    
                                     </a>
    
                                 </div>
    
                             `)
    
    +                        $(`#guild-counter-${counter}`).text(g.name)
    
    +                        $(`#owner-counter-${counter}`).text(g.owner)
    
    +                        counter += 1
    
                         }
    
                     }
    
                 }
    
    

Vulnerability mechanics

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

References

7

News mentions

0

No linked articles in our index yet.