Skip to content

Pages: require authentication and a capability to render generated standalone pages - #82254

Open
shameemreza wants to merge 3 commits into
WordPress:trunkfrom
shameemreza:fix/82251-page-template-capability-check
Open

Pages: require authentication and a capability to render generated standalone pages#82254
shameemreza wants to merge 3 commits into
WordPress:trunkfrom
shameemreza:fix/82251-page-template-capability-check

Conversation

@shameemreza

Copy link
Copy Markdown

What?

Closes #82251.

Adds an authentication and capability guard to the standalone page template in @wordpress/build, so generated pages such as font-library and options-connectors no longer render for logged-out visitors.

Why?

The page.php template hooks an interceptor to admin_init and renders the full page whenever the page query arg matches, with no capability check. admin-post.php fires admin_init for logged-out requests to support admin_post_nopriv_ actions, so any anonymous visitor could load /wp-admin/admin-post.php?page=font-library and receive the page shell, block editor scripts, and REST preload data. Reported in #82251 and in core as https://core.trac.wordpress.org/ticket/66001.

How?

  • The interceptor in page.php.template now calls auth_redirect() for logged-out visitors and wp_die() with a 403 status for users without the required capability, before rendering anything.
  • Page configs in wpPlugin.pages accept a new optional capability field, defaulting to manage_options. The build emits it through a new {{CAPABILITY}} placeholder.
  • font-library declares edit_theme_options to match the capability Core uses when registering the Fonts menu entry.
  • page-wp-admin.php.template is unchanged: it renders through add_menu_page() and add_submenu_page() callbacks, which already enforce the menu capability.

Testing Instructions

  1. Build the plugin with npm run build.
  2. Confirm build/pages/font-library/page.php guards the interceptor with is_user_logged_in() and current_user_can( 'edit_theme_options' ).
  3. Start wp-env, then log out or use curl with no cookies.
  4. Request /wp-admin/admin-post.php?page=font-library.
  5. Expected: a 302 redirect to wp-login.php with an empty body. Previously: HTTP 200 with about 21 KB of rendered editor markup.
  6. Log in as a subscriber and load the same URL. Expected: a 403 with the standard permissions message.
  7. Log in as an administrator and load the same URL. Expected: the font library page renders as before.

Unit test: npm run test:unit -- packages/wp-build/lib/test/php-generator.js.

Testing Instructions for Keyboard

Not applicable. The change adds no UI; it only gates whether the page renders.

Use of AI Tools

AI assistance: Yes.
Tool: Claude Code.
Used for: reproducing the bug, tracing the cause, and drafting the patch and tests. I reviewed and tested everything before submitting.

The page.php template hooks an interceptor to admin_init that renders
the full page whenever the page query arg matches, with no capability
check. Since admin-post.php fires admin_init for logged-out requests,
every generated standalone page was served to anonymous visitors.

Guard the interceptor with auth_redirect() and current_user_can(),
using a new capability page setting in the wp-build config that
defaults to manage_options. The font-library page declares
edit_theme_options to match its Core menu registration.

Fixes WordPress#82251
@github-actions github-actions Bot added [Package] wp-build /packages/wp-build First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository labels Aug 31, 2026
@github-actions

Copy link
Copy Markdown

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @shameemreza! In case you missed it, we'd love to have you join us in our Slack community.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

The changelog CI check requires the Unreleased entry to link the
current PR rather than the issue it fixes.
@youknowriad youknowriad added Backport to WP Minor Release Pull request that needs to be backported to a WordPress minor release [Type] Bug An existing feature does not function as intended labels Aug 31, 2026
@youknowriad

Copy link
Copy Markdown
Contributor

The other pages (site-editor-v2, theme-preview, media-editor) inherit the manage_options default while their wp-admin counterparts use edit_theme_options, switch_themes, and upload_files respectively. site-editor-v2 is the one that can bite: the Appearance → Design submenu (registered with edit_theme_options) is rewritten to point at it, so a custom role with that capability but not manage_options would see the menu item and get a 403. Worth declaring "capability" for these in package.json too, either here or as a follow-up. WDYT?

The site-editor-v2, media-editor, and theme-preview pages inherited
the manage_options default, while their menu registrations use
edit_theme_options, upload_files, and switch_themes. A user holding
the menu capability but not manage_options would see the menu entry
and get a 403. Declare the matching capability for each.

The dashboard and guidelines pages have no menu registration and the
experiments page registers with manage_options, so the default
already matches those three.
@shameemreza

Copy link
Copy Markdown
Author

Thanks @youknowriad and you're right; I only checked font-library's menu registration and left everything else on the default. Went through each one now: theme-preview registers with switch_themes, media-editor with upload_files, and the extensible site editor experiment rewrites the Design submenu URL in place, so that item keeps the edit_theme_options capability Core gave it. That last one would have been exactly the trap you describe, a custom role seeing the menu and hitting a 403.

I'd rather fix it here than in a follow-up since it's three lines of config, so I declared the matching capability for all three in 768452f. experiments already registers with manage_options, and dashboard and guidelines have no menu registration at all, so the default covers those three fine.

@shameemreza
shameemreza marked this pull request as ready for review August 31, 2026 15:04
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: shameemreza <shameemreza@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@shameemreza

Copy link
Copy Markdown
Author

@youknowriad The Playwright 8 failure is the image drag-and-drop test tracked as a flaky test in #50325, not related to this change. I don't have permission to rerun the job, so leaving it to whoever picks this up. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backport to WP Minor Release Pull request that needs to be backported to a WordPress minor release First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] wp-build /packages/wp-build [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wp-build page template renders generated admin pages without any capability check, exposing them to logged-out visitors

2 participants