Moderate severityNVD Advisory· Published Jul 29, 2014· Updated May 6, 2026
CVE-2014-3547
CVE-2014-3547
Description
Multiple cross-site scripting (XSS) vulnerabilities in badges/renderer.php in Moodle 2.5.x before 2.5.7, 2.6.x before 2.6.4, and 2.7.x before 2.7.1 allow remote attackers to inject arbitrary web script or HTML via an external badge.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
moodle/moodlePackagist | >= 2.5.0, < 2.5.7 | 2.5.7 |
moodle/moodlePackagist | >= 2.6.0, < 2.6.4 | 2.6.4 |
moodle/moodlePackagist | >= 2.7.0, < 2.7.1 | 2.7.1 |
Affected products
12cpe:2.3:a:moodle:moodle:2.5.0:*:*:*:*:*:*:*+ 11 more
- cpe:2.3:a:moodle:moodle:2.5.0:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.5.1:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.5.2:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.5.3:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.5.4:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.5.5:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.5.6:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.6.0:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.6.1:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.6.2:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.6.3:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.7.0:*:*:*:*:*:*:*
Patches
49eef6b523752MDL-46042 badges: Clean up external badge data
1 file changed · +15 −14
badges/renderer.php+15 −14 modified@@ -41,7 +41,7 @@ public function print_badges_list($badges, $userid, $profile = false, $external $bname = $badge->name; $imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1', false); } else { - $bname = $badge->assertion->badge->name; + $bname = s($badge->assertion->badge->name); $imageurl = $badge->imageUrl; } @@ -421,47 +421,48 @@ protected function render_external_badge(external_badge $ibadge) { } $datatable->data[] = array($this->output->heading(get_string('issuerdetails', 'badges'), 3), ''); - $datatable->data[] = array(get_string('issuername', 'badges'), $issuer->name); + $datatable->data[] = array(get_string('issuername', 'badges'), s($issuer->name)); $datatable->data[] = array(get_string('issuerurl', 'badges'), - html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin))); + html_writer::tag('a', s($issuer->origin), array('href' => $issuer->origin))); if (isset($issuer->contact)) { $datatable->data[] = array(get_string('contact', 'badges'), obfuscate_mailto($issuer->contact)); } $datatable->data[] = array($this->output->heading(get_string('badgedetails', 'badges'), 3), ''); - $datatable->data[] = array(get_string('name'), $assertion->badge->name); - $datatable->data[] = array(get_string('description', 'badges'), $assertion->badge->description); + $datatable->data[] = array(get_string('name'), s($assertion->badge->name)); + $datatable->data[] = array(get_string('description', 'badges'), s($assertion->badge->description)); $datatable->data[] = array(get_string('bcriteria', 'badges'), - html_writer::tag('a', $assertion->badge->criteria, array('href' => $assertion->badge->criteria))); + html_writer::tag('a', s($assertion->badge->criteria), array('href' => $assertion->badge->criteria))); $datatable->data[] = array($this->output->heading(get_string('issuancedetails', 'badges'), 3), ''); if (isset($assertion->issued_on)) { - $datatable->data[] = array(get_string('dateawarded', 'badges'), $assertion->issued_on); + $issuedate = !strtotime($assertion->issued_on) ? s($assertion->issued_on) : strtotime($assertion->issued_on); + $datatable->data[] = array(get_string('dateawarded', 'badges'), userdate($issuedate)); } - if (isset($assertion->badge->expire)) { + if (isset($assertion->expires)) { $today_date = date('Y-m-d'); $today = strtotime($today_date); - $expiration = strtotime($assertion->badge->expire); + $expiration = !strtotime($assertion->expires) ? s($assertion->expires) : strtotime($assertion->expires); if ($expiration < $today) { - $cell = new html_table_cell($assertion->badge->expire . get_string('warnexpired', 'badges')); + $cell = new html_table_cell(userdate($expiration) . get_string('warnexpired', 'badges')); $cell->attributes = array('class' => 'notifyproblem warning'); $datatable->data[] = array(get_string('expirydate', 'badges'), $cell); $image = html_writer::start_tag('div', array('class' => 'badge')); - $image .= html_writer::empty_tag('img', array('src' => $issued['badge']['image'])); + $image .= html_writer::empty_tag('img', array('src' => $issued->imageUrl)); $image .= html_writer::start_tag('span', array('class' => 'expired')) . $this->output->pix_icon('i/expired', - get_string('expireddate', 'badges', $assertion->badge->expire), + get_string('expireddate', 'badges', userdate($expiration)), 'moodle', array('class' => 'expireimage')) . html_writer::end_tag('span'); $image .= html_writer::end_tag('div'); $imagetable->data[0] = array($image); } else { - $datatable->data[] = array(get_string('expirydate', 'badges'), $assertion->badge->expire); + $datatable->data[] = array(get_string('expirydate', 'badges'), userdate($expiration)); } } if (isset($assertion->evidence)) { $datatable->data[] = array(get_string('evidence', 'badges'), - html_writer::tag('a', $assertion->evidence, array('href' => $assertion->evidence))); + html_writer::tag('a', s($assertion->evidence), array('href' => $assertion->evidence))); } $table->attributes = array('class' => 'generalbox boxaligncenter issuedbadgebox'); $table->data[] = array(html_writer::table($imagetable), html_writer::table($datatable));
0174a0a57f6dMDL-46042 badges: Clean up external badge data
1 file changed · +15 −14
badges/renderer.php+15 −14 modified@@ -41,7 +41,7 @@ public function print_badges_list($badges, $userid, $profile = false, $external $bname = $badge->name; $imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1', false); } else { - $bname = $badge->assertion->badge->name; + $bname = s($badge->assertion->badge->name); $imageurl = $badge->imageUrl; } @@ -420,47 +420,48 @@ protected function render_external_badge(external_badge $ibadge) { } $datatable->data[] = array($this->output->heading(get_string('issuerdetails', 'badges'), 3), ''); - $datatable->data[] = array(get_string('issuername', 'badges'), $issuer->name); + $datatable->data[] = array(get_string('issuername', 'badges'), s($issuer->name)); $datatable->data[] = array(get_string('issuerurl', 'badges'), - html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin))); + html_writer::tag('a', s($issuer->origin), array('href' => $issuer->origin))); if (isset($issuer->contact)) { $datatable->data[] = array(get_string('contact', 'badges'), obfuscate_mailto($issuer->contact)); } $datatable->data[] = array($this->output->heading(get_string('badgedetails', 'badges'), 3), ''); - $datatable->data[] = array(get_string('name'), $assertion->badge->name); - $datatable->data[] = array(get_string('description', 'badges'), $assertion->badge->description); + $datatable->data[] = array(get_string('name'), s($assertion->badge->name)); + $datatable->data[] = array(get_string('description', 'badges'), s($assertion->badge->description)); $datatable->data[] = array(get_string('bcriteria', 'badges'), - html_writer::tag('a', $assertion->badge->criteria, array('href' => $assertion->badge->criteria))); + html_writer::tag('a', s($assertion->badge->criteria), array('href' => $assertion->badge->criteria))); $datatable->data[] = array($this->output->heading(get_string('issuancedetails', 'badges'), 3), ''); if (isset($assertion->issued_on)) { - $datatable->data[] = array(get_string('dateawarded', 'badges'), $assertion->issued_on); + $issuedate = !strtotime($assertion->issued_on) ? s($assertion->issued_on) : strtotime($assertion->issued_on); + $datatable->data[] = array(get_string('dateawarded', 'badges'), userdate($issuedate)); } - if (isset($assertion->badge->expire)) { + if (isset($assertion->expires)) { $today_date = date('Y-m-d'); $today = strtotime($today_date); - $expiration = strtotime($assertion->badge->expire); + $expiration = !strtotime($assertion->expires) ? s($assertion->expires) : strtotime($assertion->expires); if ($expiration < $today) { - $cell = new html_table_cell($assertion->badge->expire . get_string('warnexpired', 'badges')); + $cell = new html_table_cell(userdate($expiration) . get_string('warnexpired', 'badges')); $cell->attributes = array('class' => 'notifyproblem warning'); $datatable->data[] = array(get_string('expirydate', 'badges'), $cell); $image = html_writer::start_tag('div', array('class' => 'badge')); - $image .= html_writer::empty_tag('img', array('src' => $issued['badge']['image'])); + $image .= html_writer::empty_tag('img', array('src' => $issued->imageUrl)); $image .= html_writer::start_tag('span', array('class' => 'expired')) . $this->output->pix_icon('i/expired', - get_string('expireddate', 'badges', $assertion->badge->expire), + get_string('expireddate', 'badges', userdate($expiration)), 'moodle', array('class' => 'expireimage')) . html_writer::end_tag('span'); $image .= html_writer::end_tag('div'); $imagetable->data[0] = array($image); } else { - $datatable->data[] = array(get_string('expirydate', 'badges'), $assertion->badge->expire); + $datatable->data[] = array(get_string('expirydate', 'badges'), userdate($expiration)); } } if (isset($assertion->evidence)) { $datatable->data[] = array(get_string('evidence', 'badges'), - html_writer::tag('a', $assertion->evidence, array('href' => $assertion->evidence))); + html_writer::tag('a', s($assertion->evidence), array('href' => $assertion->evidence))); } $table->attributes = array('class' => 'generalbox boxaligncenter issuedbadgebox'); $table->data[] = array(html_writer::table($imagetable), html_writer::table($datatable));
200a2b7fad3fMDL-46042 badges: Clean up external badge data
1 file changed · +15 −14
badges/renderer.php+15 −14 modified@@ -41,7 +41,7 @@ public function print_badges_list($badges, $userid, $profile = false, $external $bname = $badge->name; $imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1', false); } else { - $bname = $badge->assertion->badge->name; + $bname = s($badge->assertion->badge->name); $imageurl = $badge->imageUrl; } @@ -420,47 +420,48 @@ protected function render_external_badge(external_badge $ibadge) { } $datatable->data[] = array($this->output->heading(get_string('issuerdetails', 'badges'), 3), ''); - $datatable->data[] = array(get_string('issuername', 'badges'), $issuer->name); + $datatable->data[] = array(get_string('issuername', 'badges'), s($issuer->name)); $datatable->data[] = array(get_string('issuerurl', 'badges'), - html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin))); + html_writer::tag('a', s($issuer->origin), array('href' => $issuer->origin))); if (isset($issuer->contact)) { $datatable->data[] = array(get_string('contact', 'badges'), obfuscate_mailto($issuer->contact)); } $datatable->data[] = array($this->output->heading(get_string('badgedetails', 'badges'), 3), ''); - $datatable->data[] = array(get_string('name'), $assertion->badge->name); - $datatable->data[] = array(get_string('description', 'badges'), $assertion->badge->description); + $datatable->data[] = array(get_string('name'), s($assertion->badge->name)); + $datatable->data[] = array(get_string('description', 'badges'), s($assertion->badge->description)); $datatable->data[] = array(get_string('bcriteria', 'badges'), - html_writer::tag('a', $assertion->badge->criteria, array('href' => $assertion->badge->criteria))); + html_writer::tag('a', s($assertion->badge->criteria), array('href' => $assertion->badge->criteria))); $datatable->data[] = array($this->output->heading(get_string('issuancedetails', 'badges'), 3), ''); if (isset($assertion->issued_on)) { - $datatable->data[] = array(get_string('dateawarded', 'badges'), $assertion->issued_on); + $issuedate = !strtotime($assertion->issued_on) ? s($assertion->issued_on) : strtotime($assertion->issued_on); + $datatable->data[] = array(get_string('dateawarded', 'badges'), userdate($issuedate)); } - if (isset($assertion->badge->expire)) { + if (isset($assertion->expires)) { $today_date = date('Y-m-d'); $today = strtotime($today_date); - $expiration = strtotime($assertion->badge->expire); + $expiration = !strtotime($assertion->expires) ? s($assertion->expires) : strtotime($assertion->expires); if ($expiration < $today) { - $cell = new html_table_cell($assertion->badge->expire . get_string('warnexpired', 'badges')); + $cell = new html_table_cell(userdate($expiration) . get_string('warnexpired', 'badges')); $cell->attributes = array('class' => 'notifyproblem warning'); $datatable->data[] = array(get_string('expirydate', 'badges'), $cell); $image = html_writer::start_tag('div', array('class' => 'badge')); - $image .= html_writer::empty_tag('img', array('src' => $issued['badge']['image'])); + $image .= html_writer::empty_tag('img', array('src' => $issued->imageUrl)); $image .= html_writer::start_tag('span', array('class' => 'expired')) . $this->output->pix_icon('i/expired', - get_string('expireddate', 'badges', $assertion->badge->expire), + get_string('expireddate', 'badges', userdate($expiration)), 'moodle', array('class' => 'expireimage')) . html_writer::end_tag('span'); $image .= html_writer::end_tag('div'); $imagetable->data[0] = array($image); } else { - $datatable->data[] = array(get_string('expirydate', 'badges'), $assertion->badge->expire); + $datatable->data[] = array(get_string('expirydate', 'badges'), userdate($expiration)); } } if (isset($assertion->evidence)) { $datatable->data[] = array(get_string('evidence', 'badges'), - html_writer::tag('a', $assertion->evidence, array('href' => $assertion->evidence))); + html_writer::tag('a', s($assertion->evidence), array('href' => $assertion->evidence))); } $table->attributes = array('class' => 'generalbox boxaligncenter issuedbadgebox'); $table->data[] = array(html_writer::table($imagetable), html_writer::table($datatable));
ea76b652fc4fMDL-46042 badges: Clean up external badge data
1 file changed · +21 −20
badges/renderer.php+21 −20 modified@@ -41,7 +41,7 @@ public function print_badges_list($badges, $userid, $profile = false, $external $bname = $badge->name; $imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1', false); } else { - $bname = $badge->assertion->badge->name; + $bname = s($badge->assertion->badge->name); $imageurl = $badge->imageUrl; } @@ -381,20 +381,20 @@ protected function render_external_badge(external_badge $ibadge) { $issuer = $assertion->badge->issuer; $userinfo = $ibadge->recipient; $table = new html_table(); - $today_date = date('Y-m-d'); - $today = strtotime($today_date); - $expiration = isset($assertion->badge->expire) ? strtotime($assertion->badge->expire) : $today + 86400; + $today = strtotime(date('Y-m-d')); $output = ''; $output .= html_writer::start_tag('div', array('id' => 'badge')); $output .= html_writer::start_tag('div', array('id' => 'badge-image')); - if ($expiration < $today) { - $output .= $this->output->pix_icon('i/expired', - get_string('expireddate', 'badges', $assertion->badge->expire), - 'moodle', - array('class' => 'expireimage')); - } else { - $output .= html_writer::empty_tag('img', array('src' => $issued->imageUrl)); + $output .= html_writer::empty_tag('img', array('src' => $issued->imageUrl)); + if (isset($assertion->expires)) { + $expiration = !strtotime($assertion->expires) ? s($assertion->expires) : strtotime($assertion->expires); + if ($expiration < $today) { + $output .= $this->output->pix_icon('i/expired', + get_string('expireddate', 'badges', userdate($expiration)), + 'moodle', + array('class' => 'expireimage')); + } } $output .= html_writer::end_tag('div'); @@ -419,7 +419,7 @@ protected function render_external_badge(external_badge $ibadge) { $output .= $this->output->heading(get_string('issuerdetails', 'badges'), 3); $dl = array(); - $dl[get_string('issuername', 'badges')] = $issuer->name; + $dl[get_string('issuername', 'badges')] = s($issuer->name); $dl[get_string('issuerurl', 'badges')] = html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin)); if (isset($issuer->contact)) { @@ -429,25 +429,26 @@ protected function render_external_badge(external_badge $ibadge) { $output .= $this->output->heading(get_string('badgedetails', 'badges'), 3); $dl = array(); - $dl[get_string('name')] = $assertion->badge->name; - $dl[get_string('description', 'badges')] = $assertion->badge->description; - $dl[get_string('bcriteria', 'badges')] = html_writer::tag('a', $assertion->badge->criteria, array('href' => $assertion->badge->criteria)); + $dl[get_string('name')] = s($assertion->badge->name); + $dl[get_string('description', 'badges')] = s($assertion->badge->description); + $dl[get_string('bcriteria', 'badges')] = html_writer::tag('a', s($assertion->badge->criteria), array('href' => $assertion->badge->criteria)); $output .= $this->definition_list($dl); $output .= $this->output->heading(get_string('issuancedetails', 'badges'), 3); $dl = array(); if (isset($assertion->issued_on)) { - $dl[get_string('dateawarded', 'badges')] = $assertion->issued_on; + $issuedate = !strtotime($assertion->issued_on) ? s($assertion->issued_on) : strtotime($assertion->issued_on); + $dl[get_string('dateawarded', 'badges')] = userdate($issuedate); } - if (isset($assertion->badge->expire)) { + if (isset($assertion->expires)) { if ($expiration < $today) { - $dl[get_string('expirydate', 'badges')] = $assertion->badge->expire . get_string('warnexpired', 'badges'); + $dl[get_string('expirydate', 'badges')] = userdate($expiration) . get_string('warnexpired', 'badges'); } else { - $dl[get_string('expirydate', 'badges')] = $assertion->badge->expire; + $dl[get_string('expirydate', 'badges')] = userdate($expiration); } } if (isset($assertion->evidence)) { - $dl[get_string('evidence', 'badges')] = html_writer::tag('a', $assertion->evidence, array('href' => $assertion->evidence)); + $dl[get_string('evidence', 'badges')] = html_writer::tag('a', s($assertion->evidence), array('href' => $assertion->evidence)); } $output .= $this->definition_list($dl); $output .= html_writer::end_tag('div');
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
9- github.com/advisories/GHSA-hwjv-mc78-cccjghsaADVISORY
- moodle.org/mod/forum/discuss.phpnvdVendor AdvisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2014-3547ghsaADVISORY
- openwall.com/lists/oss-security/2014/07/21/1nvdWEB
- www.securityfocus.com/bid/68758nvdWEB
- github.com/moodle/moodle/commit/0174a0a57f6d84e240dd0bc0df0ffa63c3cc5a88ghsaWEB
- github.com/moodle/moodle/commit/200a2b7fad3f7ef92b3171a07d68df6958d842b7ghsaWEB
- github.com/moodle/moodle/commit/9eef6b5237520f0cb9874564e577c64e3a831987ghsaWEB
- github.com/moodle/moodle/commit/ea76b652fc4f3600403a61e54f198cc8570a4234ghsaWEB
News mentions
0No linked articles in our index yet.