Security: enforce CSRF token validation on state-changing admin endpoints#8600
Merged
Conversation
Refs GHSA-cxxm-wpv8-fwh9 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e0a5f2e to
2ab6607
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Several platform-admin endpoints read
$_POSTand performed privileged state changes with no anti-CSRF token validation, accepting forged cross-site submissions backed only by the admin's session cookie:admin/course_export.phpadmin/course_import.phpadmin/access_url_add_users_to_url.phpadmin/dashboard_add_courses_to_user.phpadmin/add_sessions_to_promotion.phpFix
Apply the standard Chamilo legacy CSRF idiom to each endpoint:
$_POSTprocessing branch withSecurity::check_token('post'), rejecting viaapi_not_allowed(true)when the token is missing/invalid.course_export.php,course_import.php) →$form->addHidden('sec_token', Security::get_token()).access_url_add_users_to_url.php,dashboard_add_courses_to_user.php,add_sessions_to_promotion.php) →Security::get_HTML_token(), which prints the hiddensec_tokeninput and stores it in the session.Token generation happens only on the render path, after the processing-time
check_token(), so it never overwrites the token being verified.Invariant now enforced
Each of these admin actions only runs when the request carries the per-session
sec_tokenissued when the form was rendered; cross-site forged POSTs are rejected.Notes for the reviewer
access_url_add_users_to_url.phpandadd_sessions_to_promotion.phpthe forms also auto-submit for letter/search filtering. The token check covers those submissions too (the token is part of the form), and the genuinely state-changing branches (form_sent == 1) remain gated.OWASP control
A01:2021 – Broken Access Control (CWE-352, Cross-Site Request Forgery).
Refs GHSA-cxxm-wpv8-fwh9
🤖 Generated with Claude Code