ICS Calendar <= 12.0.9 - Reflected Cross-Site Scripting via 'htmltagtitle' Parameter
Description
The ICS Calendar plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'htmltagtitle' parameter in all versions up to, and including, 12.0.9 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link. The vulnerability is reachable via the unauthenticated wp_ajax_nopriv_r34ics_ajax AJAX action, which accepts attacker-controlled js_args values merged over stored shortcode configuration without nonce verification, allowing the htmltagtitle key to bypass the normal shortcode allowlist check.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v12.0.9.2
Source Code
WordPress.org SVNThis research plan outlines the steps for a Proof-of-Concept (PoC) exploit for **CVE-2026-9838**, a reflected Cross-Site Scripting (XSS) vulnerability in the ICS Calendar plugin for WordPress. ## 1. Vulnerability Summary The **ICS Calendar** plugin (up to version 12.0.9) is vulnerable to unauthenti…
Show full research plan
This research plan outlines the steps for a Proof-of-Concept (PoC) exploit for CVE-2026-9838, a reflected Cross-Site Scripting (XSS) vulnerability in the ICS Calendar plugin for WordPress.
1. Vulnerability Summary
The ICS Calendar plugin (up to version 12.0.9) is vulnerable to unauthenticated Reflected XSS. The vulnerability exists because the unauthenticated AJAX action wp_ajax_nopriv_r34ics_ajax (located in r34ics-ajax.php) accepts a js_args parameter containing configuration overrides. These overrides are merged into the calendar's rendering configuration without sufficient sanitization or nonce verification. Specifically, the htmltagtitle parameter—intended to specify the HTML tag used for calendar titles (e.g., h2, h3)—can be manipulated to inject arbitrary HTML tags and JavaScript event handlers.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
r34ics_ajax(Unauthenticated viawp_ajax_nopriv_r34ics_ajax) - Vulnerable Parameter:
js_args[htmltagtitle] - Authentication Required: None (Unauthenticated).
- Preconditions: The plugin must be active. While the description mentions merging over "stored shortcode configuration," reflected XSS typically triggers even if a specific stored configuration is not found, as the AJAX handler attempts to render a calendar view based on the provided parameters.
3. Code Flow
- Entry Point: The request hits
admin-ajax.phpwithaction=r34ics_ajax. - AJAX Handler:
wp_ajax_nopriv_r34ics_ajaxis triggered. The handler (inr34ics-ajax.php) retrieves thejs_argsarray from the request. - Configuration Merge: The plugin merges
js_argsinto the default configuration array ($shortcode_defaultsinclass-r34ics.php). - Bypass: The AJAX path fails to apply the allowlist validation normally used when processing standard WordPress shortcodes.
- Sink: The merged configuration is passed to the rendering logic. When generating the calendar HTML, the value of
htmltagtitleis used as a literal tag name in a string concatenation or template (e.g.,<{$htmltagtitle}>... </{$htmltagtitle}>). - Reflection: The injected tag (e.g.,
img src=x onerror=alert(1)) is echoed into the HTTP response.
4. Nonce Acquisition Strategy
According to the vulnerability description, this specific AJAX action does not require nonce verification for the unauthenticated nopriv hook.
- Nonce Check: Absent or bypassed for
wp_ajax_nopriv_r34ics_ajax. - Verification: If the exploit fails with a
403 Forbiddenor0response, the PoC agent should check if a nonce is enqueued on pages containing the[ics_calendar]shortcode. - JavaScript Variable (if needed):
window.r34ics_ajax?.nonce(inferred).
5. Exploitation Strategy
The goal is to trigger an alert box in a browser context by sending a malicious htmltagtitle value via the AJAX endpoint.
Step 1: Construct the Payload
We will use an <img> tag with an onerror handler to trigger JavaScript execution.
- Payload:
img src=x onerror=alert(document.domain) - Request Parameter:
js_args[htmltagtitle]=img+src%3Dx+onerror%3Dalert(document.domain)
Step 2: Dispatch the Request
Using the http_request tool, send a POST request to the AJAX endpoint.
- Method:
POST - URL:
http://<target-ip>/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded
- Body:
action=r34ics_ajax&js_args[htmltagtitle]=img+src%3Dx+onerror%3Dalert(document.domain)&view=list
Note: Adding view=list or url=https://example.com/feed.ics (a placeholder) may be necessary to ensure the rendering engine triggers the title output.
6. Test Data Setup
- Install Plugin: Ensure ICS Calendar <= 12.0.9 is installed and activated.
- Create Feed (Optional): To ensure the rendering logic completes, it may help to have a dummy page with the shortcode.
wp post create --post_type=page --post_title="Calendar Test" --post_status=publish --post_content='[ics_calendar url="https://icscalendar.com/preview/sample.ics"]'
7. Expected Results
- HTTP Response: Status
200 OK. - Response Body: Should contain the injected payload verbatim:
<img src=x onerror=alert(document.domain)>...</img> - Browser Execution: If viewed in a browser, an alert box showing the document domain will appear.
8. Verification Steps
- Manual Verification: Use
http_requestto fetch the URL and check for the payload in the body. - Automated Check:
# Use grep to find the reflected payload in the response curl -s -X POST http://localhost:8080/wp-admin/admin-ajax.php \ -d "action=r34ics_ajax" \ -d "js_args[htmltagtitle]=vulnerable_tag" | grep "vulnerable_tag"
9. Alternative Approaches
If the htmltagtitle parameter is specifically blocked or the <img> tag fails, try other htmltag* parameters defined in class-r34ics.php:
js_args[htmltagdate]js_args[htmltageventtitle]js_args[htmltagmonth]
Payload variation for attribute breakout:
If the tag name is used inside an existing tag (e.g., <div class="<?php echo $htmltagtitle; ?>">), use:
"> <script>alert(1)</script>
Summary
The ICS Calendar plugin for WordPress is vulnerable to unauthenticated Reflected Cross-Site Scripting via the 'htmltagtitle' and other 'htmltag*' parameters. This occurs because the plugin's AJAX handler accepts configuration overrides through the 'js_args' parameter and merges them into the calendar rendering process without sufficient sanitization, allowing attackers to inject arbitrary HTML and JavaScript.
Vulnerable Code
// class-r34ics.php - Configuration defaults that are merged with user-supplied js_args // Lines 111-116 in version 12.0.9 'htmltagdate' => '', 'htmltageventdesc' => '', 'htmltageventtitle' => '', 'htmltagmonth' => '', 'htmltagtime' => '', 'htmltagtitle' => '', --- // The vulnerability resides in the AJAX handler (r34ics-ajax.php) which accepts 'js_args' // and merges them into the rendering engine's arguments without the allowlist // validation applied to standard shortcode attributes. // The values are used as literal HTML tags in the output: // <{$args['htmltagtitle']}> ... </{$args['htmltagtitle']}>
Security Fix
@@ -1,5 +1,15 @@ === ICS Calendar Changelog === += 12.0.9.2 - 2026.06.07 = + +* Changed `id` attribute on AJAX container (appended `-ajax`) so it isn't redundant with the `id` of the calendar itself after loading. + +Note: Due the fact that its single change would serve no useful purpose on its own, version 12.0.9.1 was not released in the public WordPress repository, but was included in the ICS Calendar Pro 6.1.10 update. + += 12.0.9.1 - 2026.06.02 = + +* Removed auto-redirect to settings page on activation. + = 12.0.9 - 2026.06.02 = * Security: @@ -2646,7 +2646,7 @@ 'data-view-is-list-long' => $is_list_long, 'data-view-is-list-style' => $is_list_style, 'data-view' => $args['view'] ?: '', - 'id' => $args['guid'] ?: '', + 'id' => ($args['guid'] ?: r34ics_uid()) . '-ajax', ); } @@ -3,7 +3,7 @@ Plugin Name: ICS Calendar Plugin URI: https://icscalendar.com Description: Turn your Google Calendar, Microsoft Office 365 or Apple iCloud Calendar into a seamlessly integrated, auto-updating, zero-maintenance WordPress experience. -Version: 12.0.9 +Version: 12.0.9.2 Requires at least: 5.3 Requires PHP: 7.4 Author: Room 34 Creative Services, LLC @@ -120,6 +120,7 @@ register_activation_hook(__FILE__, 'r34ics_install'); // Redirect to Getting Started page with first run message + /* add_action('admin_init', function() { if (get_option('r34ics_activation_redirect')) { // DO NOT REMOVE THIS LINE! You'll have to manually delete the plugin to stop the redirect loops @@ -128,6 +129,7 @@ exit; } }, PHP_INT_MAX - 1); + */ // Updates @@ -5,7 +5,7 @@ Requires at least: 5.3 Tested up to: 7.0 Requires PHP: 7.4 -Stable tag: 12.0.9 +Stable tag: 12.0.9.2 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -101,6 +101,16 @@ == Changelog == += 12.0.9.2 - 2026.06.07 = + +* Changed `id` attribute on AJAX container (appended `-ajax`) so it isn't redundant with the `id` of the calendar itself after loading. + +Note: Due the fact that its single change would serve no useful purpose on its own, version 12.0.9.1 was not released in the public WordPress repository, but was included in the ICS Calendar Pro 6.1.10 update. + += 12.0.9.1 - 2026.06.02 = + +* Removed auto-redirect to settings page on activation. + = 12.0.9 - 2026.06.02 = * Security:
Exploit Outline
An attacker can exploit this by sending a crafted POST request to the WordPress AJAX endpoint (/wp-admin/admin-ajax.php) using the 'r34ics_ajax' action. The payload involves passing an XSS vector (e.g., an <img> tag with an onerror event) via the 'js_args[htmltagtitle]' parameter. Because the AJAX handler does not require a nonce for unauthenticated requests and fails to validate that the provided tag name is a safe HTML element, the injected script is reflected in the AJAX response and executed when the response is rendered in the victim's browser.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.