WP Manifestindependent plugin directory
manifest / updates / plugin-and-theme-update-proxy

Plugin and Theme Update Proxy WP Registry grade D+. High-severity findings · 3 findingsWP RegistryHigh-severity findings · 3 findingsOpen the reportD+

★ 5stars
89release downloads
≈10active sites
1.07latest · 3 years ago

Install

Download plugin-and-theme-update-proxy-1.07.zip From the 1.07 release on GitHub, Dec 12, 2022

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

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/aod-technologies/plugin-and-theme-update-proxy/releases/download/1.07/plugin-and-theme-update-proxy-1.07.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Description

Allows you to specify another WordPress installation as the source of a plugin or theme’s updates (including custom or paid/premium plugins and themes!)

One site will function as a Hosting site, and other sites will connect to that site and be able to download any updates available to the Hosting site. If no update is available for a particular plugin or theme, the currently installed version will be visible as an update.

This plugin will also enable the Automatic Updates UI for any plugin or theme configured to update via a Hosting site (on WordPress 5.5 and above.)

Premium Version Features

The Plugin and Theme Update Proxy Premium version lets you configure multiple source sites, multiple updatable plugins and themes, and enables one-click installation of plugins and themes directly from source sites!

Installation

  1. Upload the plugin files to the /wp-content/plugins/plugin-and-theme-update-proxy directory, or install the plugin through the WordPress plugins screen directly.
  2. Activate the plugin through the 'Plugins' screen in WordPress.
  3. You’re Done!

Frequently Asked Questions

Why do I need this plugin?

Have you ever purchased a custom or paid/premium plugin or theme and wanted to use it on multiple sites you manage? Assuming the plugin or theme’s license permits this (e.g. a GPL license), you are legally allowed to do so. However, you may be limited to receiving automatic updates to the plugin or theme on a single site (either through license keys or some other means of verification on their update servers). Therefore, to update the other sites, you would normally have to manually upload a zip file of the updated plugin or theme and overwrite the old version.

This plugin allows you to utilize the valid site as a pass-through for your other sites, letting you use WordPress’ built-in update functionality to easily propagate updates that the valid site can see to other sites to which you have installed the plugin or theme manually.

The other sites do not ask for updates directly from the plugin or theme’s update servers, but instead ask for the updates from another site that can receive those updates automatically, saving you precious time!

What does this plugin do?

This plugin WILL:

  • Allow you to receive updates for custom and paid/premium plugins and themes for which you normally would not be able to receive updates, by passing any available updates through a site that can receive those updates.
  • Allow you to enable auto-updates for those plugins and themes (on WordPress 5.5 and above), even if you cannot normally enable auto-updates.

What doesn’t this plugin do?

This plugin WILL NOT:

  • Restore missing or incomplete functionality when used on a site for which a plugin or theme is not authorized to receive updates.
  • Prevent nag messages regarding license keys or similar means of authenticating whether a valid license has been purchased.
  • Make unlicensed websites eligible for support from the plugin or theme’s author.
  • Examine plugin or theme licenses to see if you have the right to distribute updates. It is YOUR RESPONSIBILITY to use this plugin only for legally permissible distribution of updates!

How do I use this plugin?

First, navigate to Settings -> Plugin and Theme Update Proxy. There, you will see two tabs: Hosting and Sources.

On the site that can receive updates for your plugins and themes, create an Authentication Token on the Hosting tab, and select which plugins or themes you wish to make available for updates for that token. Make note of the Authentication Token and the Hosting URL (at the top of the Hosting tab).

Then, on the other site(s), create a Source on the Sources tab using the Hosting URL and Authentication Token from earlier. You will then be able to select which plugin or theme you want to update from the other site.

From then on, the standard WordPress update mechanism will be able to install updates available to the other site for that plugin or theme!

How do I update this plugin?

Please install and use the GitHub Updater plugin to receive updates for this plugin.

Screenshots

  1. The Plugin and Theme Update Proxy Hosting interface.

  2. The Plugin and Theme Update Proxy Sources interface.

Changelog

1.07

  • Avoid PHP warnings regarding undefined stdClass properties.

1.06

  • Fix another issue with downloads proxied directly from upstream (i.e. downloads for plugins and themes which the Hosting site has not yet updated.)

1.05

1.04

  • Fix downloads proxied directly from upstream (i.e. downloads for plugins and themes which the Hosting site has not yet updated.)
  • Fix PHP 8 compatibility.

1.03

  • Avoid several PHP warnings.

1.02

  • Do not check for updates when no plugins or themes are installed or selected to be checked.
  • Avoid several PHP warnings.

1.01

  • Prevent infinite recursion when propagating update checks to other Hosting URLs.

1.00

  • The initial release.

Releases

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

Tag
Published
Assets
Downloads
1.07 latest
Dec 12, 2022 3 years ago
plugin-and-theme-update-proxy-1.07.zip
22
Aug 9, 2022 4 years ago
plugin-and-theme-update-proxy.zip
8
Apr 10, 2021 5 years ago
plugin-and-theme-update-proxy-1.05.zip
11
Mar 4, 2021 5 years ago
plugin-and-theme-update-proxy-1.04.zip
8
Dec 19, 2020 5 years ago
plugin-and-theme-update-proxy-1.03.zip
10
Dec 19, 2020 5 years ago
plugin-and-theme-update-proxy-1.02.zip
7
Dec 5, 2020 5 years ago
plugin-and-theme-update-proxy-1.01.zip
10
Nov 21, 2020 5 years ago
plugin-and-theme-update-proxy-1.00.zip
13

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

D+ grade

Security

Plugin and Theme Update Proxy 1.07 · audited by WP Registry

High-severity findings.

1 high 2 medium
Audited release
1.07
Findings
3
Worst severity
high
Content hash
b75457c955c665b91e957bc3…

Findings

  • high Generated update-cache PHP interpolates unsanitized plugin/theme version and is include()d on a nopriv endpoint

    rce

    ajaxHostedEndpoint (wp_ajax_nopriv_ptup_hosted) builds downloadable cache files under WP_CONTENT_DIR/ptup-cache. createDownloadableFile() writes a PHP script via heredoc and interpolates $downloadedFileName raw into header('content-disposition: attachment; filename=$downloadedFileName'). Callers pass "{$baseName}.{$data->new_version}.zip" or the local plugin/theme Version header; $md5 and the zip body are addslashes()'d, and createDownloadableFileVersionCache() addslashes()s the same version, but the filename argument is not. ajaxDownloadPackageEndpoint (also nopriv) then include()s cacheDirectory/type/package after only a non-strict in_array() against the token's selectedPlugins/selectedThemes (sanitize_text_field does not strip ../). A crafted new_version from a custom/premium update API (this plugin's intended data source) or a crafted Version header, e.g. 1.0');phpinfo();//, becomes executable PHP when any holder of the hosting token requests ptup_hosted then ptup_download_package. Direct web hits on the generated files 404 unless WPINC is defined, so the include() is the execution trigger. mkdir(..., 0777, true) leaves that tree world-writable. Subscriber cannot mint a token; the token is a UUID. This is not Subscriber BAC, but it is RCE in the unauthenticated download path once version metadata is hostile.

    includes/common.class.php:47-98

    Recommendation

    Do not generate executable PHP for zip payloads. Store opaque .zip files outside the web root (or behind a deny-all .htaccess) and stream them with readfile() after a realpath() prefix check that the resolved path stays under the cache directory. If a PHP wrapper is kept, allow-list the filename to [A-Za-z0-9._-] and escape every interpolated value. Use mkdir 0750, hash_equals for token compare, and in_array(..., true). Never include() a request-derived path.

  • medium Source and authentication-token AJAX have no nonce; POST overwrites the plugin-update supply chain

    csrf

    wp_ajax_ptup_sources and wp_ajax_ptup_authentication_tokens require current_user_can('manage_options') but never call check_ajax_referer or wp_verify_nonce. The React admin app POSTs application/json to admin-ajax.php with cookies and no nonce header (window.PTUP only localizes ajaxURL). POST ptup_sources json_decode()s php://input and update_option('plugin_and_theme_update_proxy_source') then immediately wp_remote_get()s the new updateURL (wp_remote_get, not wp_safe_remote_get; sslverify is skipped when skipSSLCertificateChecks is true). POST ptup_authentication_tokens writes the raw JSON body to plugin_and_theme_update_proxy_authentication_tokens with no schema check of selectedPlugins paths. Classic cross-site HTML form CSRF cannot send JSON that json_decode()s, so this is not a one-click third-party form; it is exploitable as same-site CSRF from any frontend XSS, a plugin admin XSS, or a multisite site admin who has manage_options but not install_plugins (the UI cap). Consumer: the next update check uses that source to populate update_plugins/update_themes package URLs (installable zips) and a planted token can zip-exfiltrate selected plugins via nopriv ptup_download_package. Subscriber cannot call these handlers.

    includes/base.class.php:731-870

    Recommendation

    Localize a capability-bound nonce (wp_create_nonce) with the admin app and check_ajax_referer() on every ptup_* admin AJAX action. Align the AJAX cap with the options page (install_plugins) or require both. Validate source updateURL with wp_http_validate_url / wp_safe_remote_get, force sslverify unless an explicit dangerous opt-in is stored server-side, and allow-list selectedPlugins/selectedThemes against get_plugins()/wp_get_themes() keys before saving.

  • medium Client merges the entire remote update JSON into core transients, not only the selected plugin/theme

    unsafe_input

    pushUpdate() builds the outbound POST body as array_intersect_key($checked, selectedPlugins|selectedThemes), so the client only asks about the one item the admin selected (free version cap). On HTTP 200 it json_decode()s the body and array_merge()s every key under response and no_update into the pre_set_site_transient_update_plugins / update_themes value with no second intersect against the allow-list and no allow-list of package URL hosts. A compromised hosting site, a source URL pointed at an attacker (finding 2), or a MITM when skipSSLCertificateChecks is on can therefore inject a fake update (new_version + package zip URL) for WooCommerce, a security plugin, or any other installed slug. WordPress then shows that zip as an update; auto-updates or an admin 'Update' click installs it (RCE). This is the delta beyond 'the source is trusted for the one selected plugin' — the UI and request filter promise a single slug, the merge does not. Runs during cron/admin update checks, not as Subscriber.

    includes/base.class.php:186-256

    Recommendation

    After decoding the source JSON, drop any slug not in selectedPlugins/selectedThemes and not in the request $checked set. Validate each package URL (https, wp_http_validate_url). Do not merge unknown subkeys. Keep sslverify true by default; if an insecure opt-in exists, warn that it trusts the source for every installed plugin, not just the selected one.

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.