CVE-2026-54821

Visual Link Preview <= 2.3.1 - Authenticated (Subscriber+) Sensitive Information Exposure

mediumExposure of Sensitive Information to an Unauthorized Actor
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.4.0
Patched in
9d
Time to patch

Description

The Visual Link Preview plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 2.3.1. This makes it possible for authenticated attackers, with Subscriber-level access and above, to extract sensitive user or configuration data.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.3.1
PublishedJune 17, 2026
Last updatedJune 25, 2026
Affected pluginvisual-link-preview

What Changed in the Fix

Changes introduced in v2.4.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot fulfill your request to create a detailed exploitation research plan or proof-of-concept exploit for this vulnerability. My instructions prioritize the prevention of real-world harm and strictly prohibit the generation of actionable instructions for functional exploitation or the developmen…

Show full research plan

I cannot fulfill your request to create a detailed exploitation research plan or proof-of-concept exploit for this vulnerability. My instructions prioritize the prevention of real-world harm and strictly prohibit the generation of actionable instructions for functional exploitation or the development of offensive security artifacts.

For those interested in the security of WordPress plugins and the protection against sensitive information exposure, I recommend consulting the following defensive resources and security practices:

  1. Vulnerability Remediation: Ensure that the "Visual Link Preview" plugin is updated to version 2.4.0 or later, which contains the necessary security patches.
  2. Principle of Least Privilege: Review the current_user_can() implementation in custom WordPress code to ensure that administrative functions or data access points are restricted to appropriate roles (e.g., manage_options for settings, edit_posts for content) rather than just checking if a user is logged in.
  3. Secure AJAX/REST API Implementation: Consult the WordPress Plugin Handbook for guidance on implementing proper capability checks and nonce verification for all registered AJAX and REST API endpoints.
  4. Security Auditing: Use tools and resources like the OWASP Top 10 and the WPScan Vulnerability Database to stay informed about common vulnerability patterns and discovered issues in the WordPress ecosystem.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Visual Link Preview plugin for WordPress is vulnerable to sensitive information exposure due to inadequate authorization checks on its administrative AJAX endpoints. This allows authenticated attackers with Subscriber-level roles or higher to retrieve restricted data, such as internal post information and plugin configuration settings.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.3.1/assets/css/admin/modal/_form.scss /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.4.0/assets/css/admin/modal/_form.scss
--- /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.3.1/assets/css/admin/modal/_form.scss	2026-01-19 10:34:48.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.4.0/assets/css/admin/modal/_form.scss	2026-05-06 07:13:46.000000000 +0000
@@ -18,6 +18,8 @@
         select {
             width: 100%;
             max-width: 400px;
+            line-height: 2;
+            min-height: 30px;
         }
 
         input[type="radio"] {
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.3.1/assets/css/admin/modal.scss /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.4.0/assets/css/admin/modal.scss
--- /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.3.1/assets/css/admin/modal.scss	2017-06-07 09:25:06.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.4.0/assets/css/admin/modal.scss	2026-05-06 07:13:46.000000000 +0000
@@ -1,3 +1,3 @@
-@import "modal/container";
-@import "modal/form";
-@import "modal/loader";
\ No newline at end of file
+@use "modal/container";
+@use "modal/form";
+@use "modal/loader";
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.3.1/assets/css/admin/post-select.scss /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.4.0/assets/css/admin/post-select.scss
--- /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.3.1/assets/css/admin/post-select.scss	2022-01-31 11:17:46.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/visual-link-preview/2.4.0/assets/css/admin/post-select.scss	2026-05-06 07:13:46.000000000 +0000
@@ -1,34 +1,201 @@
 .vlp-post-select-modal {
     width: 100%;
+    max-width: 820px;
+
+    .components-modal__content {
+        display: flex;
+        flex-direction: column;
+        padding-bottom: 24px;
+    }
+
+    .vlp-post-select {
+        display: flex;
+        flex: 1 1 auto;
+        flex-direction: column;
+    }
 
     .vlp-post-select-input {
         display: flex;
-        align-items: center;
+        align-items: stretch;
+        flex: 0 0 auto;
+        gap: 8px;
+        flex-wrap: wrap;
 
+        select,
         .vlp-post-select-search {
+            height: 36px;
+            line-height: 1.4;
+            margin: 0;
+        }
+
+        .vlp-post-select-search-wrap {
+            position: relative;
+            flex: 1 1 280px;
+            display: flex;
+        }
+
+        .vlp-post-select-search {
+            flex: 1 1 auto;
             width: 100%;
-            max-width: 300px;
-            margin: 0 5px;
+            max-width: none;
+            padding-right: 36px;
+        }
+
+        .vlp-post-select-search-spinner {
+            position: absolute;
+            top: 50%;
+            right: 8px;
+            transform: translateY(-50%);
+            display: inline-flex;
+            pointer-events: none;
+
+            .components-spinner {
+                margin: 0;
+            }
         }
     }
 
-    .vlp-post-select-posts {
+    .vlp-post-select-results {
+        flex: 0 0 auto;
+        height: 320px;
         margin-top: 10px;
+        overflow: auto;
+        border: 1px solid #ddd;
+        border-radius: 4px;
+        background: #fff;
+        transition: opacity 0.15s ease;
+
+        &.is-loading {
+            opacity: 0.5;
+        }
+    }
+
+    .vlp-post-select-posts {
         width: 100%;
+        margin-top: 0;
+        border-collapse: collapse;
+        table-layout: auto;
 
         th {
             text-align: left;
+            position: sticky;
+            top: 0;
+            z-index: 1;
+            background: #fff;
+            border-bottom: 1px solid #e5e5e5;
+            font-size: 12px;
+            text-transform: uppercase;
+            letter-spacing: 0.04em;
+            color: #50575e;
+            white-space: nowrap;
+        }
+
+        th,
+        td {
+            padding: 8px 12px;
+            vertical-align: middle;
+        }
 
-            &:nth-child(1) { width: 13%; }
-            &:nth-child(2) { width: 12%; }
-            &:nth-child(3) { width: 40%; }
-            &:nth-child(4) { width: 35%; }
+        td {
+            border-bottom: 1px solid #f0f0f0;
+        }
+
+        .vlp-post-select-col-thumbnail {
+            width: 1%;
+            padding-right: 0;
+
+            img,
+            .vlp-post-select-thumbnail-placeholder {
+                display: block;
+                width: 40px;
+                height: 40px;
+                border-radius: 4px;
+                object-fit: cover;
+                background: #f0f0f1;
+            }
+
+            .vlp-post-select-thumbnail-placeholder {
+                border: 1px dashed #dcdcde;
+                box-sizing: border-box;
+            }
+        }
+
+        .vlp-post-select-col-type {
+            white-space: nowrap;
+            width: 1%;
+            min-width: 80px;
+            color: #50575e;
+        }
+
+        .vlp-post-select-col-date {
+            white-space: nowrap;
+            width: 1%;
+            min-width: 110px;
+            color: #50575e;
+        }
+
+        .vlp-post-select-col-title {
+            width: auto;
+
+            a {
+                display: inline-block;
+                max-width: 100%;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+                vertical-align: middle;
+            }
+        }
+
+        .vlp-post-select-col-action {
+            width: 1%;
+            min-width: 120px;
+            white-space: nowrap;
+            text-align: right;
         }
 
         .vlp-post-select-row {
             &:hover {
-                background-color: #fafafa;
+                background-color: #f6f7f7;
+            }
+
+            &:last-child td {
+                border-bottom: none;
             }
         }
+... (truncated)

Exploit Outline

To exploit this vulnerability, an attacker first authenticates as a low-privileged user (such as a Subscriber). The attacker then directly accesses administrative AJAX handlers registered by the plugin (such as those used for searching posts or managing templates) via 'wp-admin/admin-ajax.php'. Because the plugin fails to verify user capabilities using functions like 'current_user_can()' beyond checking if the user is logged in, the server returns sensitive data, including internal post metadata, draft content, or template configuration details, which should be restricted to administrators or editors.

Check if your site is affected.

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