From b40c65f06d3958fdb5c1c67f993188d9de84831d Mon Sep 17 00:00:00 2001 From: Pan Luo Date: Thu, 27 Aug 2026 17:46:55 -0700 Subject: [PATCH] Get the user parameter in scalar context before checking permissions WeBWorK::Controller::param returns via a bare `return` when the requested parameter is not set, and a bare return yields the empty list in list context. Passing it straight into another call therefore removes the argument entirely rather than passing undef: $c->authz->hasPermissions($c->param('user'), 'access_instructor_tools') When there is no user parameter this reaches hasPermissions as a single argument, and its argument check croaks: hasPermissions called with 1 arguments instead of the expected 2: 'access_instructor_tools' ProblemSets::can('info') is reachable without a user parameter, so an unauthenticated request to the course page turns this into a server error. Assign the parameter to a scalar first, which is what the rest of this file already does, so that an unset parameter is passed through as undef and hasPermissions can answer normally. Note that the same "pass param() directly as an argument" pattern appears at a number of other hasPermissions call sites. Those are only reached once a user parameter is set, so they do not currently fail, but they are fragile for the same reason. Claude-Session: https://claude.ai/code/session_01SUWgyAFJGZD3k5gBqo7zfR --- lib/WeBWorK/ContentGenerator/ProblemSets.pm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/WeBWorK/ContentGenerator/ProblemSets.pm b/lib/WeBWorK/ContentGenerator/ProblemSets.pm index 34bcf7a34e..9a31aea095 100644 --- a/lib/WeBWorK/ContentGenerator/ProblemSets.pm +++ b/lib/WeBWorK/ContentGenerator/ProblemSets.pm @@ -30,7 +30,12 @@ sub can ($c, $arg) { my $text = DEFAULT_COURSE_INFO_TXT; eval { $text = readFile($course_info_path) } if -f $course_info_path; - return $c->authz->hasPermissions($c->param('user'), 'access_instructor_tools') + # Note that the user parameter must be obtained in scalar context. In list context the param method + # returns the empty list when the parameter is not set, and that would silently remove the argument + # from the hasPermissions call below, making it croak about being given too few arguments. + my $user = $c->param('user'); + + return $c->authz->hasPermissions($user, 'access_instructor_tools') || $text ne DEFAULT_COURSE_INFO_TXT; }