WP Manifestindependent plugin directory
manifest / email / wp-email-download

Email Download WP Registry grade D+. High-severity findings · 2 findingsWP RegistryHigh-severity findings · 2 findingsOpen the reportD+ #2 in Email & Notifications

Collect emails (or require MailChimp subscription) before allowing access to downloads.

★ 3stars
2.2krelease downloads
≈10active sites
113composer installs
v0.9latest · 2mo ago

Install

Download wp-email-download.zip From the v0.9 release on GitHub, Aug 15, 2026

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

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/dwnload/wp-email-download/releases/download/v0.9/wp-email-download.zip

On Packagist as dwnload/wp-email-download:

composer require dwnload/wp-email-download
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Allow users to download any WordPress managed file if they're subscribed to your MailChimp list

Contributors: thefrosty
Tags: wp-plugin, downloader, email-subscription, mailchimp, wp-api
Requires at least: 6.7
Tested up to: 7.1.0
Requires PHP: 8.3
Stable tag: develop
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

Mange downloads via WordPress' media manager, and use the Email Download shortcode or block to check if a users is currently subscribed to your MailChimp mailing list designated in the shortcode attribute or block config.

Shortcode

The current shortcode expects two attributes to be set; list-id=(string) and file=(int) where list-id is the ID of your MailChimp list (which you can get from the admin settings page or the shortcode builder) and the file which is the attachment ID from WordPress' media manager (again you can get this from the media screen, the post object media manager or the shortcode builder).

Example shortcode:

[email_to_download list-id="uo063u0837" file="4" /]

Installation

To install this plugin, using Composer:

composer require dwnload/wp-email-download:~0.8

Releases

Newest 25 of 26 recorded releases. Each count is every asset in that release; expand a row for the breakdown.

Tag
Published
Assets
Downloads
v0.9 latest
Aug 15, 2026 2mo ago
wp-email-download.zip +1 asset
2
wp-email-download.zip2
wp-email-download-0.9.zip0
Mar 18, 2026 7mo ago
wp-email-download.zip +1 asset
6
wp-email-download.zip2
wp-email-download-0.8.1.zip4
Nov 30, 2025 10mo ago
wp-email-download.zip +1 asset
13
wp-email-download.zip6
wp-email-download-0.8.0.zip7
Nov 30, 2025 10mo ago
wp-email-download.zip +1 asset
9
wp-email-download.zip5
wp-email-download-0.8.0-RC3.zip4
Nov 30, 2025 10mo ago
wp-email-download.zip +1 asset
5
wp-email-download.zip3
wp-email-download-0.8.0-RC2.zip2
Nov 30, 2025 10mo ago
tag only
—
Nov 2, 2023 2 years ago
wp-email-download.zip +1 asset
2,122
wp-email-download.zip3
wp-email-download-0.7.0.zip2,119
Aug 12, 2022 4 years ago
wp-email-download.zip
3
Aug 12, 2022 4 years ago
wp-email-download.zip
6
Nov 20, 2021 4 years ago
tag only
—
0.6
Nov 7, 2021 4 years ago
tag only
—
Aug 14, 2020 6 years ago
tag only
—
Feb 3, 2019 7 years ago
tag only
—
May 26, 2018 8 years ago
tag only
—
May 26, 2018 8 years ago
tag only
—
Nov 18, 2017 8 years ago
tag only
—
Nov 18, 2017 8 years ago
tag only
—
Nov 18, 2017 8 years ago
tag only
—
Nov 18, 2017 8 years ago
tag only
—
Aug 16, 2017 9 years ago
tag only
—
Aug 7, 2017 9 years ago
tag only
—
Aug 7, 2017 9 years ago
tag only
—
Aug 7, 2017 9 years ago
tag only
—
Aug 5, 2017 9 years ago
tag only
—
Jul 13, 2017 9 years ago
tag only
—
All releases on GitHub →

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

D+ grade

Security

Email Download 0.9 · audited by WP Registry

High-severity findings.

1 high 1 medium
Audited release
0.9
Findings
2
Worst severity
high
Content hash
aa784b247e0181a14ceeada6…

Findings

  • high Public REST route grants gated file downloads for any Mailchimp member email without proving ownership

    missing_auth

    POST /wp-json/dwnload/v1/user/{email} is registered through RouteService with permission_callback __return_true. The only check is wp_verify_nonce on X-WP-Nonce action wp_rest; Scripts::registerScripts localizes that nonce for every visitor (including uid 0) on pages that render the shortcode or block, and the form also outputs wp_nonce_field('wp_rest'). After decrypting the page's hidden list_id, the handler loads the site Mailchimp API key from email_download_mailchimp and GETs lists/{list_id}/members/{md5(email)}. DrewM\MailChimp treats any HTTP 2xx as success(); Mailchimp returns 200 for subscribed, unsubscribed, pending, cleaned, and archived members whenever the address exists on the list. The code never reads $response['status'] and never sends a confirmation to the mailbox. On success it builds an encrypted GET /dwnload/v1/download/{token} URL (email||hash||attachment_url||file_id||expiry, +2 days) which DownloadController serves with permission_callback __return_true and no second Mailchimp check. Distinct success vs 'It seems you're not subscribed.' is a membership oracle. Rate limiting (transient email_download_{md5(UA+LOCAL_ADDR+LOCAL_PORT+REMOTE_ADDR)}) is bypassed by changing User-Agent; a successful grant also delete_transient()s the key. Observable as unauthenticated: harvest list_id and file_id from the public form HTML, POST a guessed list member (site owner, info@, leaked audience dump), follow response.url, receive the gated attachment.

    src/RestApi/SubscriptionController.php:44-156

    Recommendation

    Do not treat knowledge of an email address as authorization. Send a one-time link to the submitted address (or require login) and only then issue the download token. Require Mailchimp status === 'subscribed'. Keep the REST route public if needed but stop using the site API key as an unauthenticated membership oracle; return a generic message in both member and non-member cases. Bind rate limits to IP (not User-Agent) and do not reset the limiter on success. Re-check membership (or a one-time token) on the download GET.

  • medium Gated file_id is not bound to the Mailchimp list, so form tokens can be swapped

    auth_bypass

    The shortcode/block render encrypted hidden fields independently: list_id = encrypt(list-id attribute) and file_id = encrypt(attachment_id || computer_id). validateUserEmailSubscription decrypts list_id for the Mailchimp member lookup, then getFileIdFromRequest() decrypts file_id and takes only explode('||', $data)[0] as absint attachment ID. The computer_id suffix from buildDataForFieldId() is never compared to the requester, and nothing checks that this file was the one configured for that list. An attacker who is a member of list B (or who can pass finding 1 with a list-B email) copies the file_id ciphertext from a list-A form on another public page and POSTs it with list B's ciphertext. wp_get_attachment_url($file_id) then feeds buildDownloadRestUrl for the list-A attachment. Concrete: two published forms, [email_to_download list-id="premium" file="10"] and [email_to_download list-id="newsletter" file="11"]; newsletter members retrieve attachment 10.

    src/Api/Api.php:89-104

    Recommendation

    Encrypt a single payload that includes list_id, file_id, and a server-side secret (or HMAC), and reject requests where the decrypted list and file do not match a stored allowlist of shortcode/block configurations. Drop the unused computer_id suffix or actually verify it. Do not accept a file_id ciphertext that did not originate with the same list_id ciphertext.

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.