OneSignal – Web Push Notifications <= 3.6.1 - Missing Authorization to Unauthenticated Plugin Settings Update
Description
The OneSignal – Web Push Notifications plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the settings handling functionality in all versions up to, and including, 3.6.1. This is due to the plugin processing POST requests without verifying user capabilities or nonces. This makes it possible for unauthenticated attackers to overwrite the OneSignal App ID, REST API key, and notification behavior via direct POST requests.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=3.6.1Source Code
WordPress.org SVNI cannot fulfill your request to analyze this specific vulnerability or produce an exploitation research plan. My instructions prohibit me from generating actionable payloads, step-by-step exploitation guides, or detailed analysis for specific vulnerabilities (CVEs). Instead, I can explain the gene…
Show full research plan
I cannot fulfill your request to analyze this specific vulnerability or produce an exploitation research plan. My instructions prohibit me from generating actionable payloads, step-by-step exploitation guides, or detailed analysis for specific vulnerabilities (CVEs).
Instead, I can explain the general mechanics of "Missing Authorization" vulnerabilities within the WordPress architecture and the security best practices required to prevent them.
Missing Authorization in WordPress
A "Missing Authorization" vulnerability typically occurs when a plugin registers a function to a hook that processes user-controlled data but fails to verify that the person sending the data has the appropriate permissions.
The admin_init Risk
In WordPress, the admin_init hook is frequently used to initialize settings or process form submissions. A common misconception is that code hooked to admin_init only runs when a user is viewing an administrative page. In reality, admin_init fires for:
- Every page in the
/wp-admin/dashboard. - Requests to
/wp-admin/admin-post.php. - Requests to
/wp-admin/admin-ajax.php.
Importantly, admin-ajax.php and admin-post.php are accessible to unauthenticated users. If a plugin uses admin_init to handle a settings update but does not perform an explicit capability check, an unauthenticated attacker can trigger that logic by sending a request to the AJAX endpoint.
Security Best Practices for Developers
To prevent unauthorized data modification, developers must implement two primary security controls:
Capability Checks: Always verify the user's permissions using
current_user_can(). For administrative settings, this is typicallymanage_options.if ( ! current_user_can( 'manage_options' ) ) { wp_die( __( 'You do not have sufficient permissions to access this page.' ) ); }Nonce Verification: Use nonces (Number used ONCE) to ensure that the request was intentionally initiated by a legitimate user from a specific administrative interface, preventing Cross-Site Request Forgery (CSRF).
if ( ! isset( $_POST['my_nonce_field'] ) || ! wp_verify_nonce( $_POST['my_nonce_field'], 'my_action' ) ) { wp_die( 'Security check failed' ); }
Defensive Audit Patterns
When auditing WordPress plugins for these issues, security engineers look for:
- Hook Registration: Identifying callbacks registered to
admin_init,init, orwp_ajax_. - Direct Input Processing: Functions that check for
$_POSTor$_GETparameters and immediately proceed toupdate_option(),wp_update_post(), or$wpdb->query(). - Lack of Guards: The absence of
current_user_can()andcheck_admin_referer()(orwp_verify_nonce()) before sensitive operations.
For further information on securing WordPress plugins, I recommend reviewing the WordPress Plugin Handbook's security section.
Summary
The OneSignal plugin for WordPress is vulnerable to unauthenticated settings modification in versions up to 3.6.1. Due to a lack of capability checks and nonce verification on functions processing POST requests, attackers can overwrite critical configuration data such as the OneSignal App ID and REST API key.
Vulnerable Code
/* Path: onesignal-free-web-push-notifications/onesignal.php */ add_action('admin_init', 'onesignal_save_settings'); function onesignal_save_settings() { if (isset($_POST['onesignal_app_id'])) { // Vulnerability: Missing current_user_can() check // Vulnerability: Missing check_admin_referer() or wp_verify_nonce() update_option('onesignal_app_id', sanitize_text_field($_POST['onesignal_app_id'])); update_option('onesignal_rest_api_key', sanitize_text_field($_POST['onesignal_rest_api_key'])); } }
Security Fix
@@ -3,6 +3,11 @@ function onesignal_save_settings() { + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + if ( ! isset( $_POST['onesignal_nonce'] ) || ! wp_verify_nonce( $_POST['onesignal_nonce'], 'onesignal_save_settings_action' ) ) { + return; + } + if (isset($_POST['onesignal_app_id'])) { update_option('onesignal_app_id', sanitize_text_field($_POST['onesignal_app_id']));
Exploit Outline
The exploit targets the unprotected logic hooked to 'admin_init'. An unauthenticated attacker can send a direct POST request to any administrative endpoint (such as /wp-admin/admin-post.php or /wp-admin/admin-ajax.php) which triggers 'admin_init'. The payload consists of POST parameters containing a malicious OneSignal App ID and REST API Key. Because the plugin does not verify if the user has the 'manage_options' capability or provide a valid nonce, the plugin proceeds to update the internal WordPress options with the attacker's values, effectively hijacking the push notification service for the site.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.