fix: gate setup wizard endpoints behind manage_options and nonces - #1354
Open
lucadobrescu wants to merge 2 commits into
Open
fix: gate setup wizard endpoints behind manage_options and nonces#1354lucadobrescu wants to merge 2 commits into
lucadobrescu wants to merge 2 commits into
Conversation
lucadobrescu
marked this pull request as ready for review
July 29, 2026 10:46
Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Co-authored-by: Cursor <cursoragent@cursor.com>
lucadobrescu
force-pushed
the
fix/wizard-endpoint-auth
branch
from
July 29, 2026 10:54
2773045 to
d58f689
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Secures setup wizard actions against low-privilege users and CSRF.
Changes:
- Adds
manage_optionschecks to dismissal and step processing. - Adds nonce protection to dismissal links.
- Adds E2E coverage for dismissal authorization.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
classes/Visualizer/Module/Wizard.php |
Enforces capabilities and nonce validation. |
templates/setup-wizard.php |
Signs the dismissal URL. |
tests/e2e/specs/wizard-auth.spec.js |
Tests unauthorized and nonce-less dismissal. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+178
to
+179
| if ( ! current_user_can( 'manage_options' ) ) { | ||
| wp_send_json( array( 'status' => 0 ), 403 ); |
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
classes/Visualizer/Module/Wizard.php:179
- The new authorization gate for the step dispatcher is not covered: the added E2E tests only exercise
visualizer_dismiss_wizard, while the existing AJAX test covers only the administrator success path. Add a valid-nonce contributor request tovisualizer_wizard_step_processand assert a 403 plus no chart/page/option side effects; otherwise the main privilege-escalation fix can regress without these tests failing.
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json( array( 'status' => 0 ), 403 );
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.
The setup wizard's dismiss action and step-processing endpoint could be invoked by any logged-in user — dismissal without any nonce, and steps with only a nonce — letting low-privilege users flip install state, create charts and draft pages, or trigger plugin installs. This gates the dismiss action behind
manage_optionsplus a nonce, and the step dispatcher behindmanage_options.What changed
Dismiss action —
admin.php?action=visualizer_dismiss_wizardnow requiresmanage_optionsand a valid nonce viacheck_admin_referer(), and the wizard template signs its dismiss link withwp_nonce_url(). Before: no nonce and no capability check — any authenticated user could flip thevisualizer_fresh_installoption and wipevisualizer_wizard_data.Step dispatcher —
visualizer_wizard_step_processrejects non-admins with 403 after the existing nonce check. One gate covers every step: chart import, plugin install, subscribe, and draft-page creation (which also deletes all post meta of the page it updates).Note
The internal
dismissWizard( false )call from the subscribe step intentionally skipscheck_admin_referer()— it is only reachable through the step dispatcher, which is already nonce- and capability-verified.Wizard request flow
flowchart LR A[Wizard request] --> B{Entry point} B -- dismiss link --> C{Changed:<br/>manage_options?}:::changed B -- step AJAX --> D{Nonce valid?} C -- no --> X[403] C -- yes --> E{New:<br/>nonce valid?}:::added E -- no --> X E -- yes --> F[Update options, redirect] D -- no --> X D -- yes --> G{New:<br/>manage_options?}:::added G -- no --> X G -- yes --> H[Run wizard step] classDef added fill:#1a7f37,color:#fff,stroke:#116329,stroke-width:3px classDef changed fill:#9a6700,color:#fff,stroke:#5c3d00,stroke-width:3px,stroke-dasharray:6 3QA
WP Admin → Users → Add New: create a Contributor user and log in as them in a private window.
As the contributor, visit
/wp-admin/admin.php?action=visualizer_dismiss_wizard&status=1.Expect: a 403 "You do not have permission to perform this action." page. Before this change, the same URL silently updated the option and redirected to the Visualizer dashboard.
Expect: the "link you followed has expired" nonce screen (403). Before, it dismissed the wizard.
wp option update visualizer_fresh_install 1), open WP Admin → Visualizer and complete the setup wizard, using the skip/dismiss link at the end.Expect: the wizard completes and dismisses normally and the Chart Library loads.