CVE-2026-3142

Pinterest Site Verification plugin using Meta Tag <= 1.8 - Authenticated (Subscriber+) Stored Cross-Site Scripting via 'post_var'

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Pinterest Site Verification plugin using Meta Tag plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'post_var' parameter in versions up to, and including, 1.8 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with subscriber-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.8
PublishedApril 7, 2026
Last updatedApril 8, 2026
Research Plan
Unverified

This research plan targets **CVE-2026-3142**, a Stored Cross-Site Scripting (XSS) vulnerability in the **Pinterest Site Verification plugin using Meta Tag** (version <= 1.8). The vulnerability allows authenticated users with Subscriber-level permissions to inject arbitrary scripts via a parameter na…

Show full research plan

This research plan targets CVE-2026-3142, a Stored Cross-Site Scripting (XSS) vulnerability in the Pinterest Site Verification plugin using Meta Tag (version <= 1.8). The vulnerability allows authenticated users with Subscriber-level permissions to inject arbitrary scripts via a parameter named post_var.


1. Vulnerability Summary

The Pinterest Site Verification plugin allows site owners to add a <meta> tag to their site's header for Pinterest domain verification. The vulnerability exists because the plugin's settings-update logic fails to perform a capability check (e.g., current_user_can('manage_options')) or properly verify nonces, and it subsequently outputs the stored value without escaping. This allows any authenticated user (including Subscribers) to overwrite the verification code with a malicious JavaScript payload.

2. Attack Vector Analysis

  • Vulnerable Endpoint: Likely wp-admin/admin-post.php or any admin page via the admin_init hook. (Inferred based on "Subscriber+" access).
  • HTTP Parameter: post_var (as specified in the CVE description).
  • Authentication Level: Subscriber (PR:L).
  • Preconditions: The attacker must be logged into WordPress as at least a Subscriber.

3. Code Flow (Inferred)

  1. Entry Point: The plugin registers a function to the admin_init hook or a wp_ajax_ action.
  2. Lack of Authorization: The handler function checks if $_POST['post_var'] is set but fails to verify if the current user has administrative privileges.
  3. Storage: The function calls update_option('pinterest_verification_code', $_POST['post_var']) (option name inferred) without sanitizing the input.
  4. Output Sink: The plugin uses the wp_head action to inject the meta tag into the frontend:
    add_action('wp_head', 'render_pinterest_meta');
    function render_pinterest_meta() {
        $code = get_option('pinterest_verification_code');
        echo '<meta name="p:domain_verify" content="' . $code . '"/>'; // VULNERABLE SINK: No esc_attr()
    }
    

4. Nonce Acquisition Strategy

If the plugin uses a nonce, it is likely exposed on the plugin's settings page. Although Subscribers typically cannot access the settings page directly, if the logic is hooked to admin_init, the nonce might be generated or checked globally.

Agent Instructions:

  1. Locate Nonce/Action: Search the plugin source for wp_create_nonce and check_admin_referer or wp_verify_nonce.
  2. Verify Access: If the nonce is required, check if it is localized via wp_localize_script.
  3. Bypass Check: Check if admin_init logic is gated by an isset($_POST['post_var']) without any nonce check. Many older plugins skip nonces for simple admin_init listeners.

5. Exploitation Strategy

The goal is to update the Pinterest verification code option using a Subscriber account and verify that it renders unescaped on the homepage.

Step-by-Step:

  1. Login as Subscriber: Obtain session cookies for a subscriber-level user.
  2. Discovery (Source Analysis):
    • Search for the string post_var in the plugin directory: grep -r "post_var" .
    • Identify the exact function name and the hook it is attached to (e.g., admin_init).
    • Note the option name used in update_option().
  3. Craft Payload:
    • The sink is inside a content attribute: <meta ... content="[PAYLOAD]"/>.
    • Payload: "><script>alert(document.domain)</script><meta name="
  4. Send Update Request:
    • Use the http_request tool to send a POST request to wp-admin/admin-post.php (or the identified endpoint).
    • Method: POST
    • URL: http://localhost:8080/wp-admin/admin-post.php (or similar)
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: post_var="><script>alert(document.domain)</script>&action=IDENTIFIED_ACTION
    • Note: If hooked to admin_init, any POST to any admin URL might trigger it.
  5. Trigger Execution:
    • Navigate to the WordPress homepage (/) using browser_navigate.
    • Check for the alert or the injected script in the source.

6. Test Data Setup

  1. Plugin Installation: Ensure pinterest-site-verification version 1.8 is active.
  2. User Creation: Create a subscriber user:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
  3. Initial State: Set a dummy verification code:
    wp option update pinterest_verification_code "12345" (Update name based on discovery).

7. Expected Results

  • The POST request from the Subscriber should return a 200 or 302 status code.
  • The wp option get [OPTION_NAME] command should reflect the XSS payload.
  • The HTML source of the homepage should contain:
    <meta name="p:domain_verify" content=""><script>alert(document.domain)</script><meta name=""/>

8. Verification Steps

  1. Verify Storage via CLI:
    wp option get pinterest_verification_code (Replace with identified option name).
  2. Verify Rendering via HTTP:
    Use http_request to GET the homepage and check if the payload exists in the <head> section without being converted to HTML entities (e.g., < should NOT be &lt;).

9. Alternative Approaches

  • Alternative Endpoint: If admin_post.php is not the target, try sending the POST request to wp-admin/index.php. If the logic is in admin_init, it will trigger on any admin page load.
  • Payload Variation: If the sink is within a specific JavaScript block rather than a meta tag, use a payload like ';alert(1);//.
  • CSRF check: If there is a nonce check but no capability check, this becomes a CSRF-to-Stored-XSS vulnerability. However, the CVE specifies "Authenticated (Subscriber+)", implying the subscriber can perform the action directly.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Pinterest Site Verification plugin using Meta Tag for WordPress is vulnerable to Stored Cross-Site Scripting via the 'post_var' parameter. This occurs because the plugin's administration logic fails to check user capabilities or nonces when saving settings and fails to escape the stored value during output. Authenticated users with subscriber-level permissions can overwrite the verification meta tag with malicious JavaScript.

Vulnerable Code

// File: pinterest-site-verification.php (inferred logic based on research plan)
// The plugin registers a global admin_init hook to handle settings updates
add_action('admin_init', 'pinterest_verify_save');

function pinterest_verify_save() {
    // Lacks check_admin_referer() for CSRF protection
    // Lacks current_user_can('manage_options') to restrict to administrators
    if (isset($_POST['post_var'])) {
        update_option('pinterest_verification_code', $_POST['post_var']);
    }
}

---

// File: pinterest-site-verification.php
// The plugin renders the stored option directly into the site's head
add_action('wp_head', 'render_pinterest_meta_tag');

function render_pinterest_meta_tag() {
    $code = get_option('pinterest_verification_code');
    if ($code) {
        // Vulnerable sink: The value is concatenated without using esc_attr()
        echo '<meta name="p:domain_verify" content="' . $code . '"/>';
    }
}

Security Fix

--- a/pinterest-site-verification.php
+++ b/pinterest-site-verification.php
@@ -2,8 +2,11 @@
 add_action('admin_init', 'pinterest_verify_save');
 
 function pinterest_verify_save() {
-    if (isset($_POST['post_var'])) {
-        update_option('pinterest_verification_code', $_POST['post_var']);
+    if (isset($_POST['post_var']) && isset($_POST['pinterest_nonce'])) {
+        if (current_user_can('manage_options') && wp_verify_nonce($_POST['pinterest_nonce'], 'save_pinterest_settings')) {
+            $sanitized_code = sanitize_text_field($_POST['post_var']);
+            update_option('pinterest_verification_code', $sanitized_code);
+        }
     }
 }
 
@@ -11,6 +14,6 @@
 
 function render_pinterest_meta_tag() {
     $code = get_option('pinterest_verification_code');
     if ($code) {
-        echo '<meta name="p:domain_verify" content="' . $code . '"/>';
+        echo '<meta name="p:domain_verify" content="' . esc_attr($code) . '"/>';
     }
 }

Exploit Outline

1. Authenticate to the WordPress site as a user with Subscriber-level privileges. 2. Craft a POST request targeting any admin URL (e.g., /wp-admin/index.php) because the plugin's update logic is hooked to 'admin_init', which triggers on every admin page load. 3. Include the parameter 'post_var' in the POST body with a payload designed to break out of the HTML attribute and inject a script, such as: "><script>alert(document.domain)</script><meta name=" 4. Submit the request. Because the plugin does not verify the user's role or a nonce, it updates the 'pinterest_verification_code' option with the malicious payload. 5. Visit the homepage of the WordPress site. The plugin will render the injected script in the <head> section, executing the JavaScript in the context of the user's browser session.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.