Multisite Security logo

Multisite Security

Organization
wpultimatesecurity
multisite-security

Use when writing code that runs on a WordPress multisite network - switch_to_blog, network admin pages, get_sites, or capabilities that differ between site and network scope. Uses manage_network / manage_network_options and is_super_admin correctly, restores context with restore_current_blog, isolates per-site data, and never trusts a blog id from input. Prevents cross-site data leakage and network privilege escalation.

Overview

Publisherwpultimatesecurity
RepositoryWordPress-Security-Skills
Skill namemultisite-security
Stars
54
Forks
3
Bundled files
2
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 2 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by wpultimatesecurity on GitHub. Read the source before you install it.

Installation

Install the Multisite Security AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/wpultimatesecurity/WordPress-Security-Skills/tree/dev/skills/multisite-security
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/wpultimatesecurity/WordPress-Security-Skills.git /tmp/WordPress-Security-Skills
mkdir -p .claude/skills
cp -r /tmp/WordPress-Security-Skills/skills/multisite-security .claude/skills/multisite-security
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Multisite Security in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Multisite Security on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Multisite Security is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

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_id from 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)

  1. 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.
  2. Always pair switch_to_blog() with restore_current_blog(). Forgetting to restore leaves the rest of the request running in the wrong site context, leaking or corrupting data.
  3. 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.
  4. Never trust a blog_id from input. Validate it against allowed sites (e.g., sites the current user belongs to, or the network allowlist) before switching.
  5. 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.
  6. is_super_admin() is for network-level checks only. Prefer current_user_can( 'manage_network' ) for capabilities.

Step-by-step implementation

  1. Check is_multisite() before running multisite-specific code.
  2. For network admin pages, gate with current_user_can( 'manage_network_options' ).
  3. For site actions that read a blog_id from 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).
  4. Wrap the operation in switch_to_blog() / restore_current_blog().
  5. After switching, re-check capabilities if the action is privileged.
  6. Return errors rather than silently failing or defaulting to the current site.

Supporting references

ReferenceLoad when
Multisite security checklistBefore final verification of the multisite security controls.
Secure multisite operationsImplementing validated site switching, membership checks, context restoration, and network option updates.

Common AI mistakes / anti-patterns

Mistake 1 — switch_to_blog() with an unvalidated blog id

php
// ❌ 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();
php
// ✅ 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()

php
// ❌ Risky: subsequent code runs in the switched context.
foreach ( $blog_ids as $blog_id ) {
    switch_to_blog( $blog_id );
    do_something();
}
php
// ✅ 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

php
// ❌ 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 );
}
php
// ✅ 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

php
// ❌ 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;
php
// ✅ 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

php
// ❌ Less precise: is_super_admin checks the super-admin list, not a capability.
if ( is_super_admin() ) {
    // do network thing
}
php
// ✅ Secure: prefer the explicit network capability.
if ( current_user_can( 'manage_network' ) ) {
    // do network thing
}

Mistake 6 — Per-site data in a network-wide cache or option

php
// ❌ Insecure: site_transient and a global cache group are shared by every
// site, so site A's private member list is served to site B's visitors.
$members = get_site_transient( 'my_plugin_members' );
if ( false === $members ) {
    $members = my_plugin_query_members();
    set_site_transient( 'my_plugin_members', $members, HOUR_IN_SECONDS );
}
php
// ✅ Secure: per-site storage (or a key that includes the blog ID).
$members = get_transient( 'my_plugin_members' );
if ( false === $members ) {
    $members = my_plugin_query_members();
    set_transient( 'my_plugin_members', $members, HOUR_IN_SECONDS );
}

Also check wp_cache_add_global_groups() calls and custom tables without a blog_id column: shared storage must never hold per-site private data.

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.

Checklist

  • Multisite-specific code checks is_multisite() first.
  • Network admin actions use manage_network / manage_network_options.
  • blog_id values 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 matching restore_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.
  • Per-site data never goes into *_site_transient, *_site_option, global cache groups, or shared tables without a blog ID in the key.
  • Users removed from a site lose access to that site's REST, AJAX, and export paths (is_user_member_of_blog() rechecked, not cached).

Official references

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Multisite Security AI skill do?

Use when writing code that runs on a WordPress multisite network - switch_to_blog, network admin pages, get_sites, or capabilities that differ between site and network scope. Uses manage_network / manage_network_options and is_super_admin correctly, restores context with restore_current_blog, isolates per-site data, and never trusts a blog id from input. Prevents cross-site data leakage and network privilege escalation.

Why use Multisite Security on TypingMind?

Because you install it once and use it with any model. Multisite Security is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Multisite Security in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/wpultimatesecurity/WordPress-Security-Skills/tree/dev/skills/multisite-security. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Multisite Security?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Multisite Security?

As many as you like. As long as a model supports skills, you can use Multisite Security with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Multisite Security AI skill free?

Yes. It is published on GitHub by wpultimatesecurity under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇