Moderate severityNVD Advisory· Published Dec 22, 2011· Updated Apr 29, 2026
CVE-2011-4203
CVE-2011-4203
Description
CRLF injection vulnerability in calendar/set.php in the Calendar component in Moodle 1.9.x before 1.9.15, 2.0.x before 2.0.6, 2.1.x before 2.1.3, and 2.2 allows remote attackers to inject arbitrary HTTP headers and conduct HTTP response splitting attacks via vectors involving the url variable.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
moodle/moodlePackagist | < 1.9.15 | 1.9.15 |
moodle/moodlePackagist | >= 2.0, < 2.0.6 | 2.0.6 |
moodle/moodlePackagist | >= 2.1, < 2.1.3 | 2.1.3 |
Affected products
24cpe:2.3:a:moodle:moodle:1.9.1:*:*:*:*:*:*:*+ 23 more
- cpe:2.3:a:moodle:moodle:1.9.1:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.10:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.11:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.12:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.13:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.14:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.2:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.3:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.4:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.5:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.6:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.7:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.8:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:1.9.9:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.0.0:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.0.2:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.0.3:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.0.4:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.0.5:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.1.0:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.1.1:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.1.2:*:*:*:*:*:*:*
- cpe:2.3:a:moodle:moodle:2.2.0:*:*:*:*:*:*:*
Patches
4ae7cc577b711MDL-29925 improve redirect url cleanup
1 file changed · +31 −23
lib/weblib.php+31 −23 modified@@ -2436,6 +2436,37 @@ function redirect($url, $message='', $delay=-1) { } } while (false); + // Technically, HTTP/1.1 requires Location: header to contain the absolute path. + // (In practice browsers accept relative paths - but still, might as well do it properly.) + // This code turns relative into absolute. + if (!preg_match('|^[a-z]+:|', $url)) { + // Get host name http://www.wherever.com + $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); + if (preg_match('|^/|', $url)) { + // URLs beginning with / are relative to web server root so we just add them in + $url = $hostpart.$url; + } else { + // URLs not beginning with / are relative to path of current script, so add that on. + $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url; + } + // Replace all ..s + while (true) { + $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); + if ($newurl == $url) { + break; + } + $url = $newurl; + } + } + + // Sanitise url - we can not rely on moodle_url or our URL cleaning + // because they do not support all valid external URLs + $url = preg_replace('/[\x00-\x1F\x7F]/', '', $url); + $url = str_replace('"', '%22', $url); + $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); + $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />', FORMAT_HTML)); + $url = str_replace('&', '&', $encodedurl); + if (!empty($message)) { if ($delay === -1 || !is_numeric($delay)) { $delay = 3; @@ -2444,26 +2475,6 @@ function redirect($url, $message='', $delay=-1) { } else { $message = get_string('pageshouldredirect'); $delay = 0; - // We are going to try to use a HTTP redirect, so we need a full URL. - if (!preg_match('|^[a-z]+:|', $url)) { - // Get host name http://www.wherever.com - $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); - if (preg_match('|^/|', $url)) { - // URLs beginning with / are relative to web server root so we just add them in - $url = $hostpart.$url; - } else { - // URLs not beginning with / are relative to path of current script, so add that on. - $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url; - } - // Replace all ..s - while (true) { - $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); - if ($newurl == $url) { - break; - } - $url = $newurl; - } - } } if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) { @@ -2473,9 +2484,6 @@ function redirect($url, $message='', $delay=-1) { } } - $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); - $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />')); - if ($delay == 0 && !$debugdisableredirect && !headers_sent()) { // workaround for IIS bug http://support.microsoft.com/kb/q176113/ if (session_id()) {
bc577df6a974MDL-29925 improve redirect url cleanup
1 file changed · +31 −23
lib/weblib.php+31 −23 modified@@ -2436,6 +2436,37 @@ function redirect($url, $message='', $delay=-1) { } } while (false); + // Technically, HTTP/1.1 requires Location: header to contain the absolute path. + // (In practice browsers accept relative paths - but still, might as well do it properly.) + // This code turns relative into absolute. + if (!preg_match('|^[a-z]+:|', $url)) { + // Get host name http://www.wherever.com + $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); + if (preg_match('|^/|', $url)) { + // URLs beginning with / are relative to web server root so we just add them in + $url = $hostpart.$url; + } else { + // URLs not beginning with / are relative to path of current script, so add that on. + $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url; + } + // Replace all ..s + while (true) { + $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); + if ($newurl == $url) { + break; + } + $url = $newurl; + } + } + + // Sanitise url - we can not rely on moodle_url or our URL cleaning + // because they do not support all valid external URLs + $url = preg_replace('/[\x00-\x1F\x7F]/', '', $url); + $url = str_replace('"', '%22', $url); + $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); + $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />', FORMAT_HTML)); + $url = str_replace('&', '&', $encodedurl); + if (!empty($message)) { if ($delay === -1 || !is_numeric($delay)) { $delay = 3; @@ -2444,26 +2475,6 @@ function redirect($url, $message='', $delay=-1) { } else { $message = get_string('pageshouldredirect'); $delay = 0; - // We are going to try to use a HTTP redirect, so we need a full URL. - if (!preg_match('|^[a-z]+:|', $url)) { - // Get host name http://www.wherever.com - $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); - if (preg_match('|^/|', $url)) { - // URLs beginning with / are relative to web server root so we just add them in - $url = $hostpart.$url; - } else { - // URLs not beginning with / are relative to path of current script, so add that on. - $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url; - } - // Replace all ..s - while (true) { - $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); - if ($newurl == $url) { - break; - } - $url = $newurl; - } - } } if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) { @@ -2473,9 +2484,6 @@ function redirect($url, $message='', $delay=-1) { } } - $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); - $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />')); - if ($delay == 0 && !$debugdisableredirect && !headers_sent()) { // workaround for IIS bug http://support.microsoft.com/kb/q176113/ if (session_id()) {
581e8dba387fMDL-29925 improve redirect url cleanup
1 file changed · +31 −23
lib/weblib.php+31 −23 modified@@ -2301,6 +2301,37 @@ function redirect($url, $message='', $delay=-1) { } } while (false); + // Technically, HTTP/1.1 requires Location: header to contain the absolute path. + // (In practice browsers accept relative paths - but still, might as well do it properly.) + // This code turns relative into absolute. + if (!preg_match('|^[a-z]+:|', $url)) { + // Get host name http://www.wherever.com + $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); + if (preg_match('|^/|', $url)) { + // URLs beginning with / are relative to web server root so we just add them in + $url = $hostpart.$url; + } else { + // URLs not beginning with / are relative to path of current script, so add that on. + $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url; + } + // Replace all ..s + while (true) { + $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); + if ($newurl == $url) { + break; + } + $url = $newurl; + } + } + + // Sanitise url - we can not rely on moodle_url or our URL cleaning + // because they do not support all valid external URLs + $url = preg_replace('/[\x00-\x1F\x7F]/', '', $url); + $url = str_replace('"', '%22', $url); + $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); + $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />', FORMAT_HTML)); + $url = str_replace('&', '&', $encodedurl); + if (!empty($message)) { if ($delay === -1 || !is_numeric($delay)) { $delay = 3; @@ -2309,26 +2340,6 @@ function redirect($url, $message='', $delay=-1) { } else { $message = get_string('pageshouldredirect'); $delay = 0; - // We are going to try to use a HTTP redirect, so we need a full URL. - if (!preg_match('|^[a-z]+:|', $url)) { - // Get host name http://www.wherever.com - $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); - if (preg_match('|^/|', $url)) { - // URLs beginning with / are relative to web server root so we just add them in - $url = $hostpart.$url; - } else { - // URLs not beginning with / are relative to path of current script, so add that on. - $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url; - } - // Replace all ..s - while (true) { - $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); - if ($newurl == $url) { - break; - } - $url = $newurl; - } - } } if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) { @@ -2338,9 +2349,6 @@ function redirect($url, $message='', $delay=-1) { } } - $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); - $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />')); - if ($delay == 0 && !$debugdisableredirect && !headers_sent()) { // workaround for IIS bug http://support.microsoft.com/kb/q176113/ if (session_id()) {
e311b1436471MDL-29925 fix calendar parameter handling
4 files changed · +57 −56
calendar/event.php+3 −3 modified@@ -49,9 +49,9 @@ $eventid = optional_param('id', 0, PARAM_INT); $eventtype = optional_param('type', 'select', PARAM_ALPHA); $urlcourse = optional_param('course', 0, PARAM_INT); - $cal_y = optional_param('cal_y'); - $cal_m = optional_param('cal_m'); - $cal_d = optional_param('cal_d'); + $cal_y = optional_param('cal_y', 0, PARAM_INT); + $cal_m = optional_param('cal_m', 0, PARAM_INT); + $cal_d = optional_param('cal_d', 0, PARAM_INT); if(isguest()) { // Guests cannot do anything with events
calendar/set.php+10 −11 modified@@ -41,15 +41,14 @@ require_once('../config.php'); require_once($CFG->dirroot.'/calendar/lib.php'); - $from = required_param('from'); - $var = required_param('var'); - $value = optional_param('value'); - $id = optional_param('id'); - $cal_d = optional_param('cal_d'); - $cal_m = optional_param('cal_m'); - $cal_y = optional_param('cal_y'); - $action = optional_param('action'); - $type = optional_param('type'); + $from = required_param('from', PARAM_ALPHA); + $var = required_param('var', PARAM_ALPHA); + $id = optional_param('id', 0, PARAM_INT); + $cal_d = optional_param('cal_d', 0, PARAM_INT); + $cal_m = optional_param('cal_m', 0, PARAM_INT); + $cal_y = optional_param('cal_y', 0, PARAM_INT); + $action = optional_param('action', '', PARAM_ALPHA); + $type = optional_param('type', '', PARAM_ALPHA); // Initialize the session variables calendar_session_vars(); @@ -107,7 +106,7 @@ switch($from) { case 'event': - redirect(CALENDAR_URL.'event.php?action='.$action.'&type='.$type.'&id='.intval($id)); + redirect(CALENDAR_URL.'event.php?action='.$action.'&type='.$type.'&id='.$id); break; case 'month': redirect(CALENDAR_URL.'view.php?view=month'.$courseid.'&cal_d='.$cal_d.'&cal_m='.$cal_m.'&cal_y='.$cal_y); @@ -119,7 +118,7 @@ redirect(CALENDAR_URL.'view.php?view=day'.$courseid.'&cal_d='.$cal_d.'&cal_m='.$cal_m.'&cal_y='.$cal_y); break; case 'course': - redirect($CFG->wwwroot.'/course/view.php?id='.intval($id)); + redirect($CFG->wwwroot.'/course/view.php?id='.$id); break; default:
calendar/view.php+16 −16 modified@@ -426,7 +426,7 @@ function calendar_show_month_detailed($m, $y, $courses, $groups, $users, $course } // Now display all the calendar - for($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) { + for($aday = 1; $aday <= $display->maxdays; ++$aday, ++$dayweek) { if($dayweek > $display->maxwday) { // We need to change week (table row) echo "</tr>\n<tr>"; @@ -436,7 +436,7 @@ function calendar_show_month_detailed($m, $y, $courses, $groups, $users, $course // Reset vars $cell = ''; - $dayhref = calendar_get_link_href(CALENDAR_URL.'view.php?view=day&course='.$courseid.'&', $day, $m, $y); + $dayhref = calendar_get_link_href(CALENDAR_URL.'view.php?view=day&course='.$courseid.'&', $aday, $m, $y); if(CALENDAR_WEEKEND & (1 << ($dayweek % 7))) { // Weekend. This is true no matter what the exact range is. @@ -448,35 +448,35 @@ function calendar_show_month_detailed($m, $y, $courses, $groups, $users, $course } // Special visual fx if an event is defined - if(isset($eventsbyday[$day])) { - if(count($eventsbyday[$day]) == 1) { + if(isset($eventsbyday[$aday])) { + if(count($eventsbyday[$aday]) == 1) { $title = get_string('oneevent', 'calendar'); } else { - $title = get_string('manyevents', 'calendar', count($eventsbyday[$day])); + $title = get_string('manyevents', 'calendar', count($eventsbyday[$aday])); } - $cell = '<div class="day"><a href="'.$dayhref.'" title="'.$title.'">'.$day.'</a></div>'; + $cell = '<div class="day"><a href="'.$dayhref.'" title="'.$title.'">'.$aday.'</a></div>'; } else { - $cell = '<div class="day">'.$day.'</div>'; + $cell = '<div class="day">'.$aday.'</div>'; } // Special visual fx if an event spans many days - if(isset($typesbyday[$day]['durationglobal'])) { + if(isset($typesbyday[$aday]['durationglobal'])) { $class .= ' duration_global'; } - else if(isset($typesbyday[$day]['durationcourse'])) { + else if(isset($typesbyday[$aday]['durationcourse'])) { $class .= ' duration_course'; } - else if(isset($typesbyday[$day]['durationgroup'])) { + else if(isset($typesbyday[$aday]['durationgroup'])) { $class .= ' duration_group'; } - else if(isset($typesbyday[$day]['durationuser'])) { + else if(isset($typesbyday[$aday]['durationuser'])) { $class .= ' duration_user'; } // Special visual fx for today - if($display->thismonth && $day == $d) { + if($display->thismonth && $aday == $d) { $class .= ' today'; } else { $class .= ' nottoday'; @@ -488,9 +488,9 @@ function calendar_show_month_detailed($m, $y, $courses, $groups, $users, $course } echo '<td'.$class.'>'.$cell; - if(isset($eventsbyday[$day])) { + if(isset($eventsbyday[$aday])) { echo '<ul class="events-new">'; - foreach($eventsbyday[$day] as $eventindex) { + foreach($eventsbyday[$aday] as $eventindex) { // If event has a class set then add it to the event <li> tag $eventclass = ''; @@ -502,9 +502,9 @@ function calendar_show_month_detailed($m, $y, $courses, $groups, $users, $course } echo '</ul>'; } - if(isset($durationbyday[$day])) { + if(isset($durationbyday[$aday])) { echo '<ul class="events-underway">'; - foreach($durationbyday[$day] as $eventindex) { + foreach($durationbyday[$aday] as $eventindex) { echo '<li>['.format_string($events[$eventindex]->name,true).']</li>'; } echo '</ul>';
lib/weblib.php+28 −26 modified@@ -6203,8 +6203,35 @@ function redirect($url, $message='', $delay=-1) { $message = clean_text($message); + // Technically, HTTP/1.1 requires Location: header to contain the absolute path. + // (In practice browsers accept relative paths - but still, might as well do it properly.) + // This code turns relative into absolute. + if (!preg_match('|^[a-z]+:|', $url)) { + // Get host name http://www.wherever.com + $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); + if (preg_match('|^/|', $url)) { + // URLs beginning with / are relative to web server root so we just add them in + $url = $hostpart.$url; + } else { + // URLs not beginning with / are relative to path of current script, so add that on. + $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url; + } + // Replace all ..s + while (true) { + $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); + if ($newurl == $url) { + break; + } + $url = $newurl; + } + } + + // Sanitise url - we can not rely on our URL cleaning + // because it does not support all valid external URLs + $url = preg_replace('/[\x00-\x1F\x7F]/', '', $url); + $url = str_replace('"', '%22', $url); $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); - $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />')); + $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />', FORMAT_HTML)); $url = str_replace('&', '&', $encodedurl); /// At developer debug level. Don't redirect if errors have been printed on screen. @@ -6226,31 +6253,6 @@ function redirect($url, $message='', $delay=-1) { /// when no message and header printed yet, try to redirect if (empty($message) and !defined('HEADER_PRINTED')) { - - // Technically, HTTP/1.1 requires Location: header to contain - // the absolute path. (In practice browsers accept relative - // paths - but still, might as well do it properly.) - // This code turns relative into absolute. - if (!preg_match('|^[a-z]+:|', $url)) { - // Get host name http://www.wherever.com - $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); - if (preg_match('|^/|', $url)) { - // URLs beginning with / are relative to web server root so we just add them in - $url = $hostpart.$url; - } else { - // URLs not beginning with / are relative to path of current script, so add that on. - $url = $hostpart.preg_replace('|\?.*$|','',me()).'/../'.$url; - } - // Replace all ..s - while (true) { - $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); - if ($newurl == $url) { - break; - } - $url = $newurl; - } - } - $delay = 0; //try header redirection first @header($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other'); //302 might not work for POST requests, 303 is ignored by obsolete clients
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
10- penturalabs.wordpress.com/2011/12/13/advisory-crlf-injection-vulnerability-in-moodle/nvdExploit
- github.com/advisories/GHSA-4w8m-96v9-2c86ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2011-4203ghsaADVISORY
- penturalabs.wordpress.com/2011/12/13/advisory-crlf-injection-vulnerability-in-moodleghsaWEB
- github.com/moodle/moodle/commit/581e8dba387f090d89382115fd850d8b44351526ghsaWEB
- github.com/moodle/moodle/commit/ae7cc577b7115a7ad7a68dc4986aca9e2bda2cf5ghsaWEB
- github.com/moodle/moodle/commit/bc577df6a974606fcb0882b090b00ea5a4e10cf6ghsaWEB
- github.com/moodle/moodle/commit/e311b14364719b0f7851149ee51c1a4ec732635eghsaWEB
- moodle.org/mod/forum/discuss.phpghsaWEB
- tracker.moodle.org/browse/MDL-24808nvd
News mentions
0No linked articles in our index yet.