VYPR
Moderate severityNVD Advisory· Published Jun 1, 2015· Updated May 6, 2026

CVE-2015-3180

CVE-2015-3180

Description

lib/navigationlib.php in Moodle through 2.5.9, 2.6.x before 2.6.11, 2.7.x before 2.7.8, and 2.8.x before 2.8.6 allows remote authenticated users to obtain sensitive course-structure information by leveraging access to a student account with a suspended enrolment.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
moodle/moodlePackagist
< 2.6.112.6.11
moodle/moodlePackagist
>= 2.7.0, < 2.7.82.7.8
moodle/moodlePackagist
>= 2.8.0, < 2.8.62.8.6

Affected products

35
  • Moodle/Moodle35 versions
    cpe:2.3:a:moodle:moodle:*:*:*:*:*:*:*:*+ 34 more
    • cpe:2.3:a:moodle:moodle:*:*:*:*:*:*:*:*range: <=2.5.9
    • 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.5.7:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.5.8:*:*:*:*:*:*:*
    • 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.10:*:*:*:*:*:*:*
    • 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.6.4:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.6.5:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.6.6:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.6.7:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.6.8:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.6.9:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.0:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.1:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.2:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.3:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.4:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.5:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.6:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.7.7:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.0:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.1:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.2:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.3:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.4:*:*:*:*:*:*:*
    • cpe:2.3:a:moodle:moodle:2.8.5:*:*:*:*:*:*:*

Patches

4
032f18c4a50d

MDL-49788 navigation: Ensure we only check active enrolments

https://github.com/moodle/moodleMarina GlancyMay 5, 2015via ghsa
1 file changed · +10 11
  • lib/navigationlib.php+10 11 modified
    @@ -1172,7 +1172,7 @@ public function initialise() {
                     // course node and not populate it.
     
                     // Not enrolled, can't view, and hasn't switched roles
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         if ($coursenode->isexpandable === true) {
                             // Obviously the situation has changed, update the cache and adjust the node.
                             // This occurs if the user access to a course has been revoked (one way or another) after
    @@ -1188,9 +1188,7 @@ public function initialise() {
                             $canviewcourseprofile = false;
                             break;
                         }
    -                }
    -
    -                if ($coursenode->isexpandable === false) {
    +                } else if ($coursenode->isexpandable === false) {
                         // Obviously the situation has changed, update the cache and adjust the node.
                         // This occurs if the user has been granted access to a course (one way or another) after initially
                         // logging in for this session.
    @@ -1235,7 +1233,7 @@ public function initialise() {
     
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
    @@ -1274,7 +1272,7 @@ public function initialise() {
     
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
    @@ -2324,7 +2322,7 @@ protected function load_for_user($user=null, $forceforcontext=false) {
                         $usercoursenode->add(get_string('notes', 'notes'), $url, self::TYPE_SETTING);
                     }
     
    -                if (can_access_course($usercourse, $user->id)) {
    +                if (can_access_course($usercourse, $user->id, '', true)) {
                         $usercoursenode->add(get_string('entercourse'), new moodle_url('/course/view.php', array('id'=>$usercourse->id)), self::TYPE_SETTING, null, null, new pix_icon('i/course', ''));
                     }
     
    @@ -2423,6 +2421,7 @@ public function add_course(stdClass $course, $forcegeneric = false, $coursetype
             } else if ($coursetype == self::COURSE_CURRENT) {
                 $parent = $this->rootnodes['currentcourse'];
                 $url = new moodle_url('/course/view.php', array('id'=>$course->id));
    +            $canexpandcourse = $this->can_expand_course($course);
             } else if ($coursetype == self::COURSE_MY && !$forcegeneric) {
                 if (!empty($CFG->navshowmycoursecategories) && ($parent = $this->rootnodes['mycourses']->find($course->category, self::TYPE_MY_CATEGORY))) {
                     // Nothing to do here the above statement set $parent to the category within mycourses.
    @@ -2502,7 +2501,7 @@ protected function can_expand_course($course) {
             $cache = $this->get_expand_course_cache();
             $canexpand = $cache->get($course->id);
             if ($canexpand === false) {
    -            $canexpand = isloggedin() && can_access_course($course);
    +            $canexpand = isloggedin() && can_access_course($course, null, '', true);
                 $canexpand = (int)$canexpand;
                 $cache->set($course->id, $canexpand);
             }
    @@ -2858,7 +2857,7 @@ public function initialise() {
                     break;
                 case self::TYPE_COURSE :
                     $course = $DB->get_record('course', array('id' => $this->instanceid), '*', MUST_EXIST);
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         // Thats OK all courses are expandable by default. We don't need to actually expand it we can just
                         // add the course node and break. This leads to an empty node.
                         $this->add_course($course);
    @@ -3252,7 +3251,7 @@ private function get_course_categories() {
                 }
                 $categories[] = $categorynode;
             }
    -        if (is_enrolled(context_course::instance($this->page->course->id))) {
    +        if (is_enrolled(context_course::instance($this->page->course->id), null, '', true)) {
                 $courses = $this->page->navigation->get('mycourses');
             } else {
                 $courses = $this->page->navigation->get('courses');
    @@ -4149,7 +4148,7 @@ protected function generate_user_settings($courseid, $userid, $gstitle='usercurr
                     }
                 } else {
                     $canviewusercourse = has_capability('moodle/user:viewdetails', $coursecontext);
    -                $userisenrolled = is_enrolled($coursecontext, $user->id);
    +                $userisenrolled = is_enrolled($coursecontext, $user->id, '', true);
                     if ((!$canviewusercourse && !$canviewuser) || !$userisenrolled) {
                         return false;
                     }
    
b7d307e80761

MDL-49788 navigation: Ensure we only check active enrolments

https://github.com/moodle/moodleMarina GlancyMay 5, 2015via ghsa
1 file changed · +10 11
  • lib/navigationlib.php+10 11 modified
    @@ -1167,7 +1167,7 @@ public function initialise() {
                     // course node and not populate it.
     
                     // Not enrolled, can't view, and hasn't switched roles
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         if ($coursenode->isexpandable === true) {
                             // Obviously the situation has changed, update the cache and adjust the node.
                             // This occurs if the user access to a course has been revoked (one way or another) after
    @@ -1183,9 +1183,7 @@ public function initialise() {
                             $canviewcourseprofile = false;
                             break;
                         }
    -                }
    -
    -                if ($coursenode->isexpandable === false) {
    +                } else if ($coursenode->isexpandable === false) {
                         // Obviously the situation has changed, update the cache and adjust the node.
                         // This occurs if the user has been granted access to a course (one way or another) after initially
                         // logging in for this session.
    @@ -1230,7 +1228,7 @@ public function initialise() {
     
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
    @@ -1269,7 +1267,7 @@ public function initialise() {
     
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
    @@ -2319,7 +2317,7 @@ protected function load_for_user($user=null, $forceforcontext=false) {
                         $usercoursenode->add(get_string('notes', 'notes'), $url, self::TYPE_SETTING);
                     }
     
    -                if (can_access_course($usercourse, $user->id)) {
    +                if (can_access_course($usercourse, $user->id, '', true)) {
                         $usercoursenode->add(get_string('entercourse'), new moodle_url('/course/view.php', array('id'=>$usercourse->id)), self::TYPE_SETTING, null, null, new pix_icon('i/course', ''));
                     }
     
    @@ -2418,6 +2416,7 @@ public function add_course(stdClass $course, $forcegeneric = false, $coursetype
             } else if ($coursetype == self::COURSE_CURRENT) {
                 $parent = $this->rootnodes['currentcourse'];
                 $url = new moodle_url('/course/view.php', array('id'=>$course->id));
    +            $canexpandcourse = $this->can_expand_course($course);
             } else if ($coursetype == self::COURSE_MY && !$forcegeneric) {
                 if (!empty($CFG->navshowmycoursecategories) && ($parent = $this->rootnodes['mycourses']->find($course->category, self::TYPE_MY_CATEGORY))) {
                     // Nothing to do here the above statement set $parent to the category within mycourses.
    @@ -2497,7 +2496,7 @@ protected function can_expand_course($course) {
             $cache = $this->get_expand_course_cache();
             $canexpand = $cache->get($course->id);
             if ($canexpand === false) {
    -            $canexpand = isloggedin() && can_access_course($course);
    +            $canexpand = isloggedin() && can_access_course($course, null, '', true);
                 $canexpand = (int)$canexpand;
                 $cache->set($course->id, $canexpand);
             }
    @@ -2853,7 +2852,7 @@ public function initialise() {
                     break;
                 case self::TYPE_COURSE :
                     $course = $DB->get_record('course', array('id' => $this->instanceid), '*', MUST_EXIST);
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         // Thats OK all courses are expandable by default. We don't need to actually expand it we can just
                         // add the course node and break. This leads to an empty node.
                         $this->add_course($course);
    @@ -3247,7 +3246,7 @@ private function get_course_categories() {
                 }
                 $categories[] = $categorynode;
             }
    -        if (is_enrolled(context_course::instance($this->page->course->id))) {
    +        if (is_enrolled(context_course::instance($this->page->course->id), null, '', true)) {
                 $courses = $this->page->navigation->get('mycourses');
             } else {
                 $courses = $this->page->navigation->get('courses');
    @@ -4137,7 +4136,7 @@ protected function generate_user_settings($courseid, $userid, $gstitle='usercurr
                     }
                 } else {
                     $canviewusercourse = has_capability('moodle/user:viewdetails', $coursecontext);
    -                $userisenrolled = is_enrolled($coursecontext, $user->id);
    +                $userisenrolled = is_enrolled($coursecontext, $user->id, '', true);
                     if ((!$canviewusercourse && !$canviewuser) || !$userisenrolled) {
                         return false;
                     }
    
8b4568500b30

MDL-49788 navigation: Ensure we only check active enrolments

https://github.com/moodle/moodleMarina GlancyMay 5, 2015via ghsa
1 file changed · +10 11
  • lib/navigationlib.php+10 11 modified
    @@ -1173,7 +1173,7 @@ public function initialise() {
                     // course node and not populate it.
     
                     // Not enrolled, can't view, and hasn't switched roles
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         if ($coursenode->isexpandable === true) {
                             // Obviously the situation has changed, update the cache and adjust the node.
                             // This occurs if the user access to a course has been revoked (one way or another) after
    @@ -1189,9 +1189,7 @@ public function initialise() {
                             $canviewcourseprofile = false;
                             break;
                         }
    -                }
    -
    -                if ($coursenode->isexpandable === false) {
    +                } else if ($coursenode->isexpandable === false) {
                         // Obviously the situation has changed, update the cache and adjust the node.
                         // This occurs if the user has been granted access to a course (one way or another) after initially
                         // logging in for this session.
    @@ -1236,7 +1234,7 @@ public function initialise() {
     
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
    @@ -1275,7 +1273,7 @@ public function initialise() {
     
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
    @@ -2328,7 +2326,7 @@ protected function load_for_user($user=null, $forceforcontext=false) {
                             $usercoursenode->add(get_string('notes', 'notes'), $url, self::TYPE_SETTING);
                         }
     
    -                    if (can_access_course($usercourse, $user->id)) {
    +                    if (can_access_course($usercourse, $user->id, '', true)) {
                             $usercoursenode->add(get_string('entercourse'), new moodle_url('/course/view.php',
                                     array('id' => $usercourse->id)), self::TYPE_SETTING, null, null, new pix_icon('i/course', ''));
                         }
    @@ -2430,6 +2428,7 @@ public function add_course(stdClass $course, $forcegeneric = false, $coursetype
             } else if ($coursetype == self::COURSE_CURRENT) {
                 $parent = $this->rootnodes['currentcourse'];
                 $url = new moodle_url('/course/view.php', array('id'=>$course->id));
    +            $canexpandcourse = $this->can_expand_course($course);
             } else if ($coursetype == self::COURSE_MY && !$forcegeneric) {
                 if (!empty($CFG->navshowmycoursecategories) && ($parent = $this->rootnodes['mycourses']->find($course->category, self::TYPE_MY_CATEGORY))) {
                     // Nothing to do here the above statement set $parent to the category within mycourses.
    @@ -2509,7 +2508,7 @@ protected function can_expand_course($course) {
             $cache = $this->get_expand_course_cache();
             $canexpand = $cache->get($course->id);
             if ($canexpand === false) {
    -            $canexpand = isloggedin() && can_access_course($course);
    +            $canexpand = isloggedin() && can_access_course($course, null, '', true);
                 $canexpand = (int)$canexpand;
                 $cache->set($course->id, $canexpand);
             }
    @@ -2865,7 +2864,7 @@ public function initialise() {
                     break;
                 case self::TYPE_COURSE :
                     $course = $DB->get_record('course', array('id' => $this->instanceid), '*', MUST_EXIST);
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         // Thats OK all courses are expandable by default. We don't need to actually expand it we can just
                         // add the course node and break. This leads to an empty node.
                         $this->add_course($course);
    @@ -3270,7 +3269,7 @@ private function get_course_categories() {
             }
     
             // Don't show the 'course' node if enrolled in this course.
    -        if (!is_enrolled(context_course::instance($this->page->course->id))) {
    +        if (!is_enrolled(context_course::instance($this->page->course->id, null, '', true))) {
                 $courses = $this->page->navigation->get('courses');
                 if (!$courses) {
                     // Courses node may not be present.
    @@ -4166,7 +4165,7 @@ protected function generate_user_settings($courseid, $userid, $gstitle='usercurr
                     }
                 } else {
                     $canviewusercourse = has_capability('moodle/user:viewdetails', $coursecontext);
    -                $userisenrolled = is_enrolled($coursecontext, $user->id);
    +                $userisenrolled = is_enrolled($coursecontext, $user->id, '', true);
                     if ((!$canviewusercourse && !$canviewuser) || !$userisenrolled) {
                         return false;
                     }
    
271477f593c4

MDL-49788 navigation: Ensure we only check active enrolments

https://github.com/moodle/moodleMarina GlancyMay 5, 2015via ghsa
1 file changed · +10 11
  • lib/navigationlib.php+10 11 modified
    @@ -1167,7 +1167,7 @@ public function initialise() {
                     // course node and not populate it.
     
                     // Not enrolled, can't view, and hasn't switched roles
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         if ($coursenode->isexpandable === true) {
                             // Obviously the situation has changed, update the cache and adjust the node.
                             // This occurs if the user access to a course has been revoked (one way or another) after
    @@ -1183,9 +1183,7 @@ public function initialise() {
                             $canviewcourseprofile = false;
                             break;
                         }
    -                }
    -
    -                if ($coursenode->isexpandable === false) {
    +                } else if ($coursenode->isexpandable === false) {
                         // Obviously the situation has changed, update the cache and adjust the node.
                         // This occurs if the user has been granted access to a course (one way or another) after initially
                         // logging in for this session.
    @@ -1230,7 +1228,7 @@ public function initialise() {
     
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
    @@ -1269,7 +1267,7 @@ public function initialise() {
     
                     // If the user is not enrolled then we only want to show the
                     // course node and not populate it.
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         $coursenode->make_active();
                         $canviewcourseprofile = false;
                         break;
    @@ -2311,7 +2309,7 @@ protected function load_for_user($user=null, $forceforcontext=false) {
                         $usercoursenode->add(get_string('notes', 'notes'), $url, self::TYPE_SETTING);
                     }
     
    -                if (can_access_course($usercourse, $user->id)) {
    +                if (can_access_course($usercourse, $user->id, '', true)) {
                         $usercoursenode->add(get_string('entercourse'), new moodle_url('/course/view.php', array('id'=>$usercourse->id)), self::TYPE_SETTING, null, null, new pix_icon('i/course', ''));
                     }
     
    @@ -2410,6 +2408,7 @@ public function add_course(stdClass $course, $forcegeneric = false, $coursetype
             } else if ($coursetype == self::COURSE_CURRENT) {
                 $parent = $this->rootnodes['currentcourse'];
                 $url = new moodle_url('/course/view.php', array('id'=>$course->id));
    +            $canexpandcourse = $this->can_expand_course($course);
             } else if ($coursetype == self::COURSE_MY && !$forcegeneric) {
                 if (!empty($CFG->navshowmycoursecategories) && ($parent = $this->rootnodes['mycourses']->find($course->category, self::TYPE_MY_CATEGORY))) {
                     // Nothing to do here the above statement set $parent to the category within mycourses.
    @@ -2489,7 +2488,7 @@ protected function can_expand_course($course) {
             $cache = $this->get_expand_course_cache();
             $canexpand = $cache->get($course->id);
             if ($canexpand === false) {
    -            $canexpand = isloggedin() && can_access_course($course);
    +            $canexpand = isloggedin() && can_access_course($course, null, '', true);
                 $canexpand = (int)$canexpand;
                 $cache->set($course->id, $canexpand);
             }
    @@ -2845,7 +2844,7 @@ public function initialise() {
                     break;
                 case self::TYPE_COURSE :
                     $course = $DB->get_record('course', array('id' => $this->instanceid), '*', MUST_EXIST);
    -                if (!can_access_course($course)) {
    +                if (!can_access_course($course, null, '', true)) {
                         // Thats OK all courses are expandable by default. We don't need to actually expand it we can just
                         // add the course node and break. This leads to an empty node.
                         $this->add_course($course);
    @@ -3239,7 +3238,7 @@ private function get_course_categories() {
                 }
                 $categories[] = $categorynode;
             }
    -        if (is_enrolled(context_course::instance($this->page->course->id))) {
    +        if (is_enrolled(context_course::instance($this->page->course->id), null, '', true)) {
                 $courses = $this->page->navigation->get('mycourses');
             } else {
                 $courses = $this->page->navigation->get('courses');
    @@ -4129,7 +4128,7 @@ protected function generate_user_settings($courseid, $userid, $gstitle='usercurr
                     }
                 } else {
                     $canviewusercourse = has_capability('moodle/user:viewdetails', $coursecontext);
    -                $userisenrolled = is_enrolled($coursecontext, $user->id);
    +                $userisenrolled = is_enrolled($coursecontext, $user->id, '', true);
                     if ((!$canviewusercourse && !$canviewuser) || !$userisenrolled) {
                         return false;
                     }
    

Vulnerability mechanics

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

References

12

News mentions

0

No linked articles in our index yet.