Skip to content

Fix CSRF in ajax.php enabling privilege escalation by requiring sessk… - #3391

Open
Patryk Mroczko (patmr7) wants to merge 1 commit into
MOODLE_502_STABLEfrom
wip-135837-m502
Open

Fix CSRF in ajax.php enabling privilege escalation by requiring sessk…#3391
Patryk Mroczko (patmr7) wants to merge 1 commit into
MOODLE_502_STABLEfrom
wip-135837-m502

Conversation

@patmr7

Copy link
Copy Markdown
Collaborator

…ey validation

local/o365/ajax.php required only require_login() and moodle/site:config, with no sesskey check on any of its state-changing modes. mode_checkteamsmoodlesetup in particular enables web services, the REST protocol, frame embedding, the bundled o365_webservices external service, and grants moodle/webservice:createtoken and webservice/rest:use to the default authenticated-user role - all unconditionally, on a simple GET request. A forged cross-site request against a logged-in administrator (e.g. via an tag) silently expands these permissions to every authenticated user, regardless of whether the site uses Teams SSO at all.

Add require_sesskey() to ajax.php, and append sesskey to the ajax.php URL built by the three admin_setting classes that call it (moodlesetup, verifysetup, serviceresource). These build their AJAX calls with plain jQuery rather than a sesskey-aware core JS module, so the sesskey is carried in the URL's query string instead, where jQuery's GET request serialization appends the remaining parameters.

…ey validation

local/o365/ajax.php required only require_login() and moodle/site:config, with no
sesskey check on any of its state-changing modes. mode_checkteamsmoodlesetup in
particular enables web services, the REST protocol, frame embedding, the bundled
o365_webservices external service, and grants moodle/webservice:createtoken and
webservice/rest:use to the default authenticated-user role - all unconditionally,
on a simple GET request. A forged cross-site request against a logged-in
administrator (e.g. via an <img> tag) silently expands these permissions to every
authenticated user, regardless of whether the site uses Teams SSO at all.

Add require_sesskey() to ajax.php, and append sesskey to the ajax.php URL built by
the three admin_setting classes that call it (moodlesetup, verifysetup,
serviceresource). These build their AJAX calls with plain jQuery rather than a
sesskey-aware core JS module, so the sesskey is carried in the URL's query string
instead, where jQuery's GET request serialization appends the remaining
parameters.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the local_o365 admin AJAX endpoint against CSRF by enforcing Moodle sesskey validation and ensuring the admin-setting UI includes a sesskey when calling the endpoint.

Changes:

  • Add require_sesskey() to local/o365/ajax.php to block CSRF against state-changing modes.
  • Append sesskey to the /local/o365/ajax.php URL used by the three admin setting UI widgets (moodlesetup, verifysetup, serviceresource).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
local/o365/ajax.php Enforces sesskey validation for all AJAX modes.
local/o365/classes/adminsetting/moodlesetup.php Includes sesskey in the AJAX endpoint URL passed to the JS widget.
local/o365/classes/adminsetting/verifysetup.php Includes sesskey in the AJAX endpoint URL passed to the JS widget.
local/o365/classes/adminsetting/serviceresource.php Includes sesskey in the AJAX endpoint URL passed to the JS widget.
Suppressed comments (1)

local/o365/classes/adminsetting/moodlesetup.php:99

  • The JS widget (moodlesetup.js) references opts.strerrorcheck when rendering errors, but this options object never sets that key. In error cases the UI will display undefined instead of a localized error message.
        $ajaxurl = new url('/local/o365/ajax.php', ['sesskey' => sesskey()]);
        $settinghtml .= '<script>
                            $(function() {
                                var opts = {
                                    url: "' . $ajaxurl->out() . '",

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread local/o365/ajax.php
Comment on lines 30 to +33
require_login();
$mode = required_param('mode', PARAM_TEXT);
require_capability('moodle/site:config', system::instance());
require_sesskey();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants