User tests: Successful: Unsuccessful:
Pull Request resolves # .
The ajax.fetchUserState task in com_guidedtours persists tour state for the current user: it writes to #__user_profiles (guidedtour.id.<id> -> completed / skipped / delayed) and dispatches the onBeforeTourSaveUserState / onAfterTourSaveUserState plugin events. The component dispatcher deliberately skips the usual access check for this task so every logged-in backend user can record their own tour progress -- but the controller never validated the session CSRF token, accepting plain GET requests with no token at all.
This PR adds a Session::checkToken('get') guard at the start of fetchUserState(), following the same pattern as the other core Ajax controllers (e.g. com_categories fetchAssociations), and sends the token from the guided tours script, which already receives it as the com_guidedtours.token script option. Fail-closed: a missing or wrong token returns an invalid-token JSON error. Only the source file (build/media_source/...) is touched; the compiled asset in media/ is gitignored and built.
The tid / sid parameters are integers and context is whitelisted, so the token check was the only missing piece.
ajax.fetchUserState request now carries the session token (&<token>=1 in the URL).ajax.fetchUserState accepted plain GET requests with no CSRF token: a malicious page could flip any logged-in administrator's tour state (completed / skipped / delayed) via CSRF, and any low-privilege backend user could hit the endpoint directly.
Requests without a valid session CSRF token are rejected with an invalid-token JSON error; legitimate requests carrying the token work exactly as before.
Please select:
Documentation link for guide.joomla.org:
No documentation changes for guide.joomla.org needed
Pull Request link for manual.joomla.org:
No documentation changes for manual.joomla.org needed
| Status | New | ⇒ | Pending |
| Category | ⇒ | Administration JavaScript Repository NPM Change |
Please use the required/given PR description template : https://github.com/joomla/joomla-cms/blob/5.4-dev/.github/PULL_REQUEST_TEMPLATE.md
Done -- PR description updated to follow the template, including the Generative AI policy checkbox and testing instructions.
I have tested this item ✅ successfully on afee660
Tested with JBT
GET https://localhost:7154/administrator/index.php?option=com_guidedtours&task=ajax.fetchUserState&format=json&tid=12&sid=6&context=tour.completenpm run build:js
user_profiles tablehttps://localhost:7154/administrator/index.php?option=com_guidedtours&task=ajax.fetchUserState&format=json&2c3427c84ce0428aa22437c98d808dd1=1&tid=12&sid=6&context=tour.complete"state":"completed"is createduser_profiles tableuser_profiles table{"success":false,"message":"The most recent request was denied because it had an invalid security token. Please refresh the page and try again.","messages":null,"data":null}I have tested this item ✅ successfully on afee660
Tested with JBT
GET https://localhost:7154/administrator/index.php?option=com_guidedtours&task=ajax.fetchUserState&format=json&tid=12&sid=6&context=tour.completenpm run build:js
user_profiles tablehttps://localhost:7154/administrator/index.php?option=com_guidedtours&task=ajax.fetchUserState&format=json&2c3427c84ce0428aa22437c98d808dd1=1&tid=12&sid=6&context=tour.complete"state":"completed"is createduser_profiles tableuser_profiles table{"success":false,"message":"The most recent request was denied because it had an invalid security token. Please refresh the page and try again.","messages":null,"data":null}
Please the required/given PR description template : https://github.com/joomla/joomla-cms/blob/5.4-dev/.github/PULL_REQUEST_TEMPLATE.md