Install
$ agentstack add skill-wpultimatesecurity-wordpress-security-skills-multisite-security ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Multisite security
When to use this skill
Use this skill whenever code runs on a WordPress multisite network:
- Using
switch_to_blog()to access another site's data. - Adding network admin pages (
network_admin_menu). - Enumerating sites with
get_sites(). - Reading a
blog_idfrom a request parameter or URL. - Performing actions that affect the whole network vs. a single site.
On multisite, site administrator and network administrator are different roles. Network-level actions require manage_network or manage_network_options, and switch_to_blog() must always be paired with restore_current_blog().
Related: see the capability-permission-checks skill for single-site capability patterns.
Core principles (and why they matter)
- Site admin != network admin. A site administrator can do almost anything on their
own site, but they must not manage network settings or access other sites' data. Network actions need manage_network / manage_network_options.
- Always pair
switch_to_blog()withrestore_current_blog(). Forgetting to restore
leaves the rest of the request running in the wrong site context, leaking or corrupting data.
- Re-check capabilities after switching. Capabilities are evaluated in the current
site context. After switch_to_blog(), the capability context changes; re-verify current_user_can() or user_can() if you act on the new site.
- Never trust a
blog_idfrom input. Validate it against allowed sites (e.g., sites
the current user belongs to, or the network allowlist) before switching.
- Keep per-site data isolated. Do not store site A's data in site B's options or
tables unless the user explicitly authorized cross-site access.
is_super_admin()is for network-level checks only. Prefercurrent_user_can( 'manage_network' )
for capabilities.
Step-by-step implementation
- Check
is_multisite()before running multisite-specific code. - For network admin pages, gate with
current_user_can( 'manage_network_options' ). - For site actions that read a
blog_idfrom input:
- Cast to integer.
- Confirm the site exists (
get_site()). - Confirm the current user may act on it (
user_can( $user_id, 'manage_sites' )or
membership checks).
- Wrap the operation in
switch_to_blog()/restore_current_blog(). - After switching, re-check capabilities if the action is privileged.
- Return errors rather than silently failing or defaulting to the current site.
Common AI mistakes / anti-patterns
Mistake 1 — switch_to_blog() with an unvalidated blog id
// ❌ Insecure: any blog id can be requested, including sites the user does not own.
$blog_id = (int) $_GET['blog_id'];
switch_to_blog( $blog_id );
$posts = get_posts();
restore_current_blog();
// ✅ Secure: validate the blog id and the user's relationship to it.
$blog_id = isset( $_GET['blog_id'] ) ? absint( $_GET['blog_id'] ) : 0;
$site = get_site( $blog_id );
if ( ! $site || ! is_user_member_of_blog( get_current_user_id(), $blog_id ) ) {
wp_die( esc_html__( 'Invalid site.', 'my-plugin' ), 403 );
}
switch_to_blog( $blog_id );
$posts = get_posts();
restore_current_blog();
Mistake 2 — Forgetting restore_current_blog()
// ❌ Risky: subsequent code runs in the switched context.
foreach ( $blog_ids as $blog_id ) {
switch_to_blog( $blog_id );
do_something();
}
// ✅ Secure: restore after each switch.
foreach ( $blog_ids as $blog_id ) {
switch_to_blog( $blog_id );
do_something();
restore_current_blog();
}
Mistake 3 — Using manage_options for a network action
// ❌ Insecure: site admins have manage_options but cannot manage the network.
if ( current_user_can( 'manage_options' ) ) {
update_site_option( 'my_plugin_network_key', $value );
}
// ✅ Secure: network actions require manage_network / manage_network_options.
if ( ! current_user_can( 'manage_network_options' ) ) {
wp_die( esc_html__( 'You do not have permission to manage network options.', 'my-plugin' ), 403 );
}
update_site_option( 'my_plugin_network_key', $value );
Mistake 4 — Leaking data after a switch
// ❌ Insecure: data fetched under site B is echoed on site A without re-checking.
switch_to_blog( $blog_id );
$title = get_bloginfo( 'name' );
restore_current_blog();
echo $title;
// ✅ Secure: validate the user may read the target site, then escape output.
if ( ! is_user_member_of_blog( get_current_user_id(), $blog_id ) ) {
return;
}
switch_to_blog( $blog_id );
$title = get_bloginfo( 'name' );
restore_current_blog();
echo esc_html( $title );
Mistake 5 — Assuming is_super_admin() covers every case
// ❌ Less precise: is_super_admin checks the super-admin list, not a capability.
if ( is_super_admin() ) {
// do network thing
}
// ✅ Secure: prefer the explicit network capability.
if ( current_user_can( 'manage_network' ) ) {
// do network thing
}
Correct code examples
A complete network-safe routine that validates a blog id, switches context, and restores it is in [references/secure-multisite-operations.php](references/secure-multisite-operations.php).
Checklist
- [ ] Multisite-specific code checks
is_multisite()first. - [ ] Network admin actions use
manage_network/manage_network_options. - [ ]
blog_idvalues from input are cast to integers and validated. - [ ] The user is confirmed to be a member of / allowed on the target site before switching.
- [ ] Every
switch_to_blog()has a matchingrestore_current_blog(). - [ ] Capabilities are re-checked after switching sites if the action is privileged.
- [ ] Per-site data is not leaked into another site's context.
- [ ]
is_super_admin()is used only where the super-admin list is the correct gate.
Official references
is_multisite()is_super_admin()current_user_can()user_can()switch_to_blog()restore_current_blog()get_sites()get_current_blog_id()network_admin_menuhookis_user_member_of_blog()- Multisite Network Administration
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: wpultimatesecurity
- Source: wpultimatesecurity/WordPress-Security-Skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.