WP Manifestindependent plugin directory
manifest / updates / wp-juggler-server

WP Juggler Server WP Registry grade D. High-severity findings · 6 findingsWP RegistryHigh-severity findings · 6 findingsOpen the reportD

WP Juggler: A robust, free, open-source WordPress Management System, allows you to command and control unlimited number of WordPress sites through a single, self-hosted control panel. With swift and seamless setup, WP Juggler frees you from the painstaking upkeep of individual WordPress instances, giving you more time to focus on what you do best.

★ 2stars
47release downloads
≈10active sites
1.1.4latest · 2 years ago

Install

Download wp-juggler-server.zip From the 1.1.4 release on GitHub, Oct 17, 2024

Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/boldthemes/wp-juggler-server/releases/download/1.1.4/wp-juggler-server.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

WP Juggler

WP Juggler is your ultimate solution for effectively managing an unlimited portfolio of WordPress sites from a single, intuitive dashboard.

WP Juggler helps you to enhance your operational efficiency, ensure your sites stay current with updates, and reclaim precious time to focus on more impactful projects.

Being an open-source and completely free tool, WP Juggler is designed to revolutionize your WordPress maintenance experience without costing you a dime.

The idea behind it

WP Juggler is a product of BoldThemes' need to efficiently manage more than 100 demo sites showcasing our premium WordPress themes and more than 200 websites resulting from our agency work.

Before the creation of WP Juggler, managing multiple sites was a chaotic, time-consuming process that often resulted in costly maintenance issues. The solutions available in the market were either inadquate, overpriced or fell short in efficient functionality.

So we have created WP Juggler

Screenshot of WP Juggler Control Panel

Why choose WP Juggler?

There are more than few reasons to consider WP Juggler over existing commercial products. With WP Juggler you can:

  • Track WP Health and WP Debug info for all your WordPress sites
  • Seamlessly login into wp-admin panel of your sites with a single click
  • Set up uptime monitor and receive alerts when your sites stop responding
  • Manage your WordPress plugins - update, activate and deactivate them in bulk from a central point
  • Host your own plugins in your network and update them as if they were hosted on wordpress.org
  • For additional security, verify checksums of installed plugins, themes and WP Core and receive alerts on all failed checks
  • Track known vulnerabilities of current versions of your plugins and themes and avoid being hacked
  • Manage and update themes from a central point
  • Track WordPress wp-admin dashboard notices for all your WordPress sites
  • Set granular user rights to control who sees what within your network

Screenshot of WP Juggler Plugins screen

WP Juggler is fully compatible with WordPress multisite setups.

It also makes TGMPA plugins fully integreted into WordPress update mechanism.

This is important if you have premium themes (such as ones coming from ThemeForest) installed on your sites. Their packaged plugins will be treated the same way as all other plugins in your WordPress installations.

Screenshot of WP Juggler Site Health Info

How does it work - Main concepts

WP Juggler has two components:

[!NOTE] WP Juggler Server is a self-hosted WordPress plugin which features control panel for centralized WordPress management of your sites.

This means that the data governance within your network is entirely under your control.

Network setup - as easy as one, two, three

You can setup your WP Juggler Network in three simple steps:

  1. Kickstart the process by installing the WP Juggler Server Plugin on one of your WordPress sites
  2. Install WP Juggler Client plugins on sites you want to control and manage
  3. Register and activate your sites on your server with a single mouse click

Complete User Documentation

You can find the complete User Documentation on this link: https://documentation.bold-themes.com/wp-juggler/ but you can also find the Getting Started intructions below.

Getting Started Guide

Install plugins

  1. Download wp-juggler-server.zip file from the latest release of WP Juggler Server plugin.
  2. Install and Activate WP Juggler Server plugin on one of your WordPress sites. This site will serve as your control panel.
  3. Download wp-juggler-client.zip file from the latest release of WP Juggler Client plugin.
  4. Install and Activate WP Juggler Client plugin on WordPress sites you want to monitor and manage remotely.

Add new site

  1. Navigate to WP Juggler > Sites in your server's wp-admin and click Add New
  2. Enter the site name as title, enter the site url.
  3. Click Assign Users and add the users who will be able to manage the added site (add your user for start).
  4. Click Save and copy API Key to clipboard

Activate new site

  1. Navigate to WP Juggler screen in your client site's wp-admin and enter bith API Key and server's url
  2. Click Save Settings. You will should see the message that your site is successfully activated
  3. If the activation fails and the Auth Header Test Row also says "Failed", do as instructed in the section Enable PHP HTTP Authorization Header

Screenshot of WP Juggler Site Edit Screen

Fetch your first data

  1. Navigate to WP Juggler > Control Panel in your server's wp-admin and your newly activated site should appear in the list.
  2. Click the arrow at the end of its row to expand the panel and click Refresh All Site Data
  3. Once the refresh finishes you will be able to see the summary of the data retrieved from your site.
  4. Explore the available info by clicking buttons in the expansion panel

Enable one-click login to wp-admin

  1. Navigate to WP Juggler > Sites in your server's wp-admin and edit the desired site.
  2. Check Automatic Login, enter Remote Login Username (username of the user you are going to log in on the target site) and click Save
  3. On your client site, edit the User's profile and check Enable auto login for this user.
  4. We are all set. You can test the login by first logging out of the client site's wp-admin.
  5. Lastly, go to your control panel and click wp-admin button in your site's row. You should be automatically logged in as chosen user.

Setup your crons

WP Juggler uses WP Cron system to automatically refresh remote site data.

You can set the refresh frequency by navigating to WP Juggler > Settings in your server's wp-admin.

[!IMPORTANT] The WordPress cron system is activated automatically based on a page view / init action. This means that if you do not have visits on your server site, the WP Cron will not fire and no data will be automatically retreived. This includes uptime crons.

Screenshot of WP Juggler Uptime screen

Solution for crons

Therefore it is best to set up a cronjob to call the wp-cron.php file in the root of your server WordPress install every 5 minutes, otherwise your scheduled tasks may not run correctly.

Depending on your hosting environment, there is more than one way to do this.

Here is the general explanation from WordPress plugin handbook on how to this: Hooking WP-Cron Into the System Task Scheduler

On most hostings you can do this on your hosting control panel or hosting dashboard. Here is the explanation from SiteGround.

Contact your hosting support if needed.

Screenshot of WP Juggler Dashboard Screen

Enable PHP HTTP Authorization Header

[!Note] This section describes the actions that need to be taken if the Auth Header Test says Failed either on Server or Client side

Shared Hosts

Most shared hosts have disabled the HTTP Authorization Header by default.

To enable this option you'll need to edit your .htaccess file by adding the following:

RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]

just after

RewriteEngine on

WPEngine

To enable this option you'll need to edit your .htaccess file by adding the following (see #1):

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

ToDo List

If you have a feature proposal or an idea on how to make WP Juggler better and more useful, please use Issues section. We will be glad to review them and add them to the list.

Currenty opened development tasks:

  • [x] Alert emails when front end or API is down
  • [x] Remote plugin installation
  • [ ] Retrieve and set Site Option values
  • [ ] Vulnerability check of installed themes and WP Core
  • [ ] Checksum verification of themes from WordPress.org

Releases

7 releases. Each count is every asset in that release; expand a row for the breakdown.

Tag
Published
Assets
Downloads
1.1.4 latest
Oct 17, 2024 2 years ago
wp-juggler-server.zip
24
Oct 17, 2024 2 years ago
wp-juggler-server.zip
7
Oct 15, 2024 2 years ago
wp-juggler-server.zip
5
Oct 8, 2024 2 years ago
wp-juggler-server.zip
5
Oct 7, 2024 2 years ago
wp-juggler-server.zip
2
Sep 30, 2024 2 years ago
wp-juggler-server.zip
1
Sep 30, 2024 2 years ago
wp-juggler-server.zip
3

Active-site estimate ≈10 comes from the median of recent superseded releases. Method.

D grade

Security

WP Juggler Server 1.1.4 · audited by WP Registry

High-severity findings.

3 high 3 medium
Audited release
1.1.4
Findings
6
Worst severity
high
Content hash
eb59ab422a5829884ea0670b…

Findings

  • high Site and plugin CPTs use post capabilities, exposing fleet API keys and auto-login to Editors

    missing_capability

    wpjugglersites, wpjugglerplugins, and wpjugglertools are registered with capability_type 'post' and an empty capabilities array (inline TODO to fix create/edit caps). show_in_menu=>'wpjs-dashboard' only hides the menu for users without manage_options; it does not block /wp-admin/edit.php?post_type=wpjugglersites or post.php. Editors (edit_others_posts) can open any managed-site post and read the API key and remote login username rendered in the metabox, change wp_juggler_server_site_url / automatic login / ping URL, and save via wpjs_save_sites_meta_boxes which only checks edit_post. wpjs_generate_login_token signs an HS256 JWT with that API key and claim wpjs_username, which the client accepts for one-click wp-admin login. Editors can also publish wpjugglerplugins packages that serve_manifest exposes at /wpjs-plugins/, poisoning the private update channel. Authors can create their own site records. This is below manage_options and is the path to takeover of every connected client.

    includes/class-wpjs-admin.php:281-306

    Recommendation

    Register all three CPTs with a dedicated capability (e.g. capability_type 'wpjugglersite' mapped to manage_options, or cap 'manage_options' on every primitive). Keep show_ui behind the same cap. Do not print API keys into HTML for anyone who cannot manage the fleet; show a masked value and rotate only via a manage_options+nonce AJAX handler that also checks get_post_type($id)==='wpjugglersites'.

  • high CSRF on fleet plugin install/activate/update AJAX (no nonce)

    csrf

    State-changing wp_ajax handlers that drive the client (wpjs-install-plugin, wpjs-activate-plugin, wpjs-deactivate-plugin, wpjs-update-plugin, wpjs-update-theme, wpjs-refresh-*, wpjs-start-cron) check only current_user_can('manage_options'). They never call wp_verify_nonce / check_ajax_referer, unlike ajax_save_settings. A cross-site POST to admin-ajax.php with the administrator's cookies (SameSite=Lax still sends on top-level form POST) invokes WPJS_Service::install_plugin($site_id, $plugin_url), which POSTs attacker-controlled pluginUrl to the client's /wp-json/juggler/v1/installPlugin. That is remote code execution on every managed site whose siteId the attacker can guess or enumerate from a prior CP session. Activate/deactivate/update similarly mutate client plugins. wp_create_nonce('wpjs-control-panel') is localized into the Vue app but is not consumed by these PHP handlers.

    includes/class-wpjs-ajax.php:1970-1986

    Recommendation

    Require check_ajax_referer (or wp_verify_nonce against the localized wpjs-control-panel nonce) on every state-changing AJAX handler before calling the client. Restrict installPlugin URLs to an allowlist (attachment IDs on this site or wordpress.org slugs). Do not accept an arbitrary pluginUrl from the request.

  • high Broken nonce and edit_posts gate lets Contributors rotate any site API key

    missing_capability

    wpjs_reset_api_key is registered as wp_ajax_juggler_reset_api_key. It calls wp_verify_nonce($this->plugin_name, '-site', $nonce): WordPress's signature is wp_verify_nonce($nonce, $action), so this verifies the literal string 'wpjs' as a nonce for action '-site' and ignores the POST token; the boolean result is discarded. The only gate is current_user_can('edit_posts') — Contributor, Author, and Editor pass. There is no current_user_can('edit_post', $post_id), no post-type check, and no manage_options. Any such user (or a CSRF form against their session, including an administrator) can POST an arbitrary post_id, overwrite wp_juggler_api_key with a fresh UUID, and receive that secret in the JSON response. That disconnects the matching client (DoS of the management channel) and, combined with CPT edit access, lets an Editor plant a key they control. wpjs_user_search has the same broken wp_verify_nonce($this->plugin_name, '-user', $nonce) pattern.

    includes/class-wpjs-ajax.php:1711-1738

    Recommendation

    Call if (!wp_verify_nonce($_POST['wp_juggler_server_nonce'], 'wpjs-site')) wp_die(). Require current_user_can('manage_options') and get_post_type($post_id)==='wpjugglersites' (or current_user_can('edit_post',$post_id) after CPT caps are fixed). Do not return the new key to roles that should not see it.

  • medium Unauthenticated /wpjs-plugins/ manifest dumps private plugin packages

    information_disclosure

    serve_manifest is hooked to template_redirect with no is_user_logged_in, capability, or shared-secret check. Any GET whose path is exactly /wpjs-plugins/ (hardcoded; the wpjs_cp_slug option is unused) loads every published wpjugglerplugins post and echoes JSON including version, slug, and download_url from wp_get_attachment_url. The README presents this as a private in-network plugin host. Clients need a fetchable manifest, but listing every package at a well-known unauthenticated URL plus typical public /wp-content/uploads/ attachment URLs lets anyone download proprietary/internal zips (license material, hardcoded endpoints) and learn which plugins the fleet runs. Inline TODO notes a planned temp-URL flow that was never implemented.

    includes/class-wpjs-plugins.php:53-121

    Recommendation

    Authenticate the manifest (client API key or a per-site signed token) or issue short-lived, unguessable download URLs as the TODO describes. Do not list all slugs to anonymous callers; require the slug and a token. Store packages outside the public uploads tree or gate them with a capability/token download handler.

  • medium Client API calls disable TLS verification while sending Bearer API keys

    insecure_config

    WPJS_Service::call_client_api is the single outbound path for health/debug/checksum/plugin install/activate/update and auto-activation. It POSTs JSON to {site_url}/wp-json/juggler/v1/{endpoint} with Authorization: Bearer {wp_juggler_api_key} and sslverify => false, with an inline comment 'TODO SHOULD BE REMOVED FOR PRODUCTION'. check_front_end uses the same flag. A network attacker who can MITM the server-to-client path (captive portal, broken middlebox, DNS hijack of a managed host) reads every site's API key and can rewrite installPlugin bodies. Combined with HS256 auto-login JWTs keyed by that secret, stolen keys become one-click admin sessions on the client. This is compiled into the 1.1.4 release, not a dev-only branch.

    includes/class-wpjs-service.php:140-150

    Recommendation

    Enable sslverify (true) for all wp_remote_* calls. If local/dev exceptions are required, gate them on an explicit development constant, not a shipped default.

  • medium Any client API key authorizes leftover fleet-wide REST cron endpoints

    unnecessary_attack_surface

    juggler/v1/triggerMultiCron, checkClientApi, and triggerSingleCron use permission_callback api_validate_api_key, which only checks that the Bearer token matches some wpjugglersites row. It does not bind the caller to that site_id. triggerMultiCron then runs check_all_plugins_checksum_api() against every activated site. checkClientApi runs the full uptime loop. triggerSingleCron ignores the authenticated site entirely and always calls WPJS_Service::check_notices_api(37) (hardcoded debug IDs in comments: 'mac 5' / 'firma 37'), then wp_send_json_success of that site's notice payload. A leaked key from one low-value client therefore triggers jobs (and notice exfil for post 37) across the fleet. These routes look like unfinished operator debug, not the client activation handshake (activateSite).

    includes/class-wpjs-api.php:169-217

    Recommendation

    Remove triggerSingleCron/triggerMultiCron/checkClientApi from the public REST API, or require a server-side operator nonce/capability. If a client must call back, authorize only that site_id and never run check_all_* or hardcoded post IDs.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.