22 Apr 2025

WordPress Plugin Security Review: Popup Builder

For our 47th security review of a WordPress plugin based on the voting of our customers, we reviewed the plugin Popup Builder.

If you are not yet a customer of the service, once you sign up for the service as a paying customer, you can start suggesting and voting on plugins to get security reviews. For those already using the service that haven’t already suggested and voted for plugins to receive a review, you can start doing that here. You can use our tool for doing limited automated security checks of plugins to see if plugins you are using have possible issues that would make them good candidates to get a review. You can also order a review of a plugin separately from our service.

The review was done on version 4.3.7 of Popup Builder. We checked for the following issues during it as part of our standard review:

  • Insecure file upload handling (this is the cause of the most exploited type of vulnerability, arbitrary file upload)
  • Deserialization of untrusted data
  • Security issues with functions accessible through WordPress’ AJAX functionality (those have and continued to be a common source of disclosed vulnerabilities)
  • Security issues with functions accessible through WordPress’ REST API (those have started to be a source of disclosed vulnerabilities)
  • Persistent cross-site scripting (XSS) vulnerabilities in the frontend portions of the plugin and in the admin portions accessible to users with the Author role or below
  • Cross-site request forgery (CSRF) vulnerabilities in the admin portion of the plugin
  • SQL injection vulnerabilities (the code that handles requests to the database)
  • Reflected cross-site scripting (XSS) vulnerabilities
  • Security issues with functions accessible through any of the plugin’s shortcodes
  • Security issues with functions accessible through any of the plugin’s blocks
  • Security issues with functions accessible through the admin_action action
  • Security issues with functions accessible through the admin_init action
  • Security issues with functions accessible through the admin_post action
  • Security issues with import/export functionality
  • Security issues with usage of the is_admin() function
  • Security issues with usage of the add_option(), delete_option(), and update_option() functions
  • Security issues with usage of the update_user_meta() and wp_update_user() functions
  • Security with usage of determine_current_user filter
  • Security issues with usage of the wp_set_current_user(), wp_set_auth_cookie() and wc_set_customer_auth_cookie() functions
  • Security issues with usage of the reset_password() and wp_set_password() functions
  • Security issues with usage of the extract() function
  • Lack of IP address validation
  • Proper usage of sanitize_callback when using register_setting() to register settings
  • Existence of register_uninstall_hook or uninstall.php file that removes any WordPress options and database tables added by the plugin
  • CSV injection
  • Host header injection vulnerabilities
  • Lack of protection against unintended direct access of PHP files
  • Insecure and unwarranted requests to third-party websites
  • Any additional possible issues identified by our Plugin Security Checker

Results

We found several minor vulnerabilities, as well as places where the security could be improved.

We notified the developer of the results on March 8, offered them free help to address the issues, and informed them of our disclosure policy. We haven’t heard back from them. They did release a new version several days after we contacted them, but it didn’t address the issue. Under our disclosure policy, we should have disclosed the results a week ago, but we gave them another week due to the holiday. So we are now disclosing the results.

Cross-Site Request Forgery (CSRF) Vulnerability

In the file /public/views/settings.php, the following code lacks a nonce check to prevent cross-site request forgery (CSRF):

30
31
32
33
34
35
36
37
if( isset( $_GET['hide_warning'] ) && $_GET['hide_warning'] == true )
{
	update_option('sgpb-hide_disable-custom-js-warning', 1);
	echo '<style>.notice_sgpb.sgpb_dsiable_notice{ display: none !important;}</style>';
}
if( isset( $_GET['hide_injection'] ) && $_GET['hide_injection'] == true )
{
	update_option('sgpb-hide_disable-injection-warning', 1);

Missing Capability Checks

In the file /com/classes/Updates.php, the function sgpbActivateLicense() lacks a capability check for this code:

17
18
19
20
if (isset($_POST['sgpb-license-key-'.$key])) {
	$this->sgpbVerifyNonceLicense();				
	$this->sanitizeLicense(sanitize_key($_POST['sgpb-license-key-'.$key]));
}

There is a missing capability check in the functions dismissNotification(), removeNotification(), and reactivateNotification() in the file /com/classes/NotificationCenter.php. That is also true in the function sgpbDeactivateFeedback() in the file /com/classes/Feedback.php.

Security Issues in Library

The plugin is using an outdated version of the jQuery Validation library that contains security issues according to the developer:

Upgrading that library would resolve that. The library is located at /public/js/Validate.js.

Lack of Duplication Restriction

The function popupSaveAsNew() in the file /com/classes/Actions.php doesn’t restrict what can be duplicated to only content from the plugin.

 Server-Side Request Forgery (SSRF).

The function getImageDataFromUrl() in /com/helpers/AdminHelper.php and the function checkSameOrigin() in the file /com/classes/Ajax.php use the function wp_remote_get() with an arbitrary URL. The wp_safe_remote_get() should probably be used there to prevent the possibility of server-side request forgery (SSRF).

Nonce Leakage

The plugin included a bunch of content from the plugin, including nonces, on all admin pages of the websites for all users. So, for example, someone logged in as a subscriber is getting multiple nonces even though they have access to nothing from the plugin. It would be much better to only load things on pages that they are needed on and only for relevant users.

Improper Sanitization

The function getPopupId() in the file /com/classes/ConditionCreator.php is setting the value of the GET input “post” to a variable. It looks like the value should be limited to an integer, but is sanitized as text instead.

In the file /com/classes/Actions.php, in the function getSubscribersCsvFile() the plugin checks if the value of $_GET[‘order’] is allowed after running it through sanitize_text_field(), but then use it with it run through sanitize_text_field() and wp_unslash(). That could potentially cause something not intended to be used in a SQL statement. Though, we didn’t see a way that can be done. The code would be more secure by using the relevant WordPress security function sanitize_sql_orderby() on that portion of the SQL statement.

maybe_unserialize()

The plugin is using the maybe_unserialize() function, which is known to be insecure and a Core Committer of WordPress said plugins shouldn’t be using it.

CSV Injection

When exporting subscribers to a CSV file, there isn’t protection against CSV injection.

Improper wp_ajax_nopriv Registration

The function sgpbSubsciptionFormSubmittedAction() is made AJAX accessible to those not logged in to WordPress using wp_ajax_nopriv registration, but the function itself limits access to those logged in, so it seems making it available to those not logged in is wrong.

Directory Access Restriction Issue

The plugin limits access to the files in the directory /wp-content/uploads/subscribersimportsgpb/ with a .htaccess file. That doesn’t have any effect with web servers that don’t utilize .htaccess files, including NGINX. Including a notice when that directory exists and an incompatible server is being used, telling the webmaster they should implement protection compatible with the server would improve security.

Tracking Without Consent

Guideline 7 of the WordPress Plugin Directory states that “In the interest of protecting user privacy, plugins may not contact external servers without explicit and authorized consent.” The function updateNotificationsArray() in the file /com/classes/NotificationCenter.php is making a request to the developer’s website without checking for consent.

Incomplete Uninstall

When the plugin is deleted, the code that runs in the function uninstall() in the file /com/helpers/AdminHelper.php is failing to remove all the options set by the plugin.

Lack of Protection Against Direct Access to PHP Files

Some of the plugin’s .php files do not have code at the beginning of the files to restrict direct access to them. We didn’t see anything that could be exploited in the files without the restriction in place, but adding the code the plugin already has in other files would make things more secure.

Possible Access to Unfiltered HTML to Users with Access

One final issue that we didn’t report to the developer, but should be noted, is that the plugin, by default, allows users given access to the plugin’s admin functionality to add JavaScript code to popups. By default only Administrators have access, but if users with a role below Editor were given access, they would have access to doing the equivalent of cross-site scripting (XSS) without the unfiltered_html capability. The ability to include JavaScript code can be disabled in the plugin’s settings. It would probably be better to rely on whether users have the unfiltered_html capability to decide if they have access to that functionality.


Plugin Security Scorecard Grade for Popup Builder

Checked on September 28, 2024
C+

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

Leave a Reply

Your email address will not be published. Required fields are marked *