GWD Connect <= 2.9 - Unauthenticated Limited Code Execution via update_agent
Description
The GWD Connect plugin for WordPress is vulnerable to missing authorization to limited code execution in all versions up to, and including, 2.9. This is due to the plugin's standalone agent endpoints (gwd-backup.php and gwd-logs.php) not verifying authentication when the API key has not been configured, which is the default state. This makes it possible for unauthenticated attackers - on unregistered installations only, in certain environments - to execute arbitrary code on the server via the update_agent action, which writes attacker-supplied PHP code to the agent file.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:NTechnical Details
<=2.9This research plan targets **CVE-2026-6663**, a missing authorization vulnerability in the **GWD Connect** plugin. The vulnerability allows unauthenticated attackers to overwrite plugin files with arbitrary PHP code when the plugin is in its default, unconfigured state. --- ### 1. Vulnerability Su…
Show full research plan
This research plan targets CVE-2026-6663, a missing authorization vulnerability in the GWD Connect plugin. The vulnerability allows unauthenticated attackers to overwrite plugin files with arbitrary PHP code when the plugin is in its default, unconfigured state.
1. Vulnerability Summary
The GWD Connect plugin includes standalone PHP files (gwd-backup.php and gwd-logs.php) designed to act as "agents" for remote management. These files are intended to be secured by an API key. However, in versions up to 2.9, the logic fails to verify authentication if the API key has not yet been configured in the WordPress database (the default state). An attacker can invoke the update_agent action to overwrite the agent file itself with malicious PHP code, leading to Remote Code Execution (RCE).
2. Attack Vector Analysis
- Endpoints:
/wp-content/plugins/graphic-web-design-inc/gwd-backup.php/wp-content/plugins/graphic-web-design-inc/gwd-logs.php
- Vulnerable Action:
update_agent - Parameters:
action: Must be set toupdate_agent.key: The API key (vulnerable when empty or omitted if the plugin is unconfigured).code(inferred): The parameter containing the PHP code to be written to the file.
- Preconditions: The plugin must be installed, but the "GWD API Key" must not be set in the plugin settings.
- Authentication: None required (Unauthenticated).
3. Code Flow (Inferred from Description)
- Entry Point: A direct request is made to
gwd-backup.php. Because this is a standalone file, it likely does not load the full WordPress environment (wp-load.php) immediately, or it loads it after its own auth checks. - Auth Bypass: The script checks the provided
keyparameter against a stored option (e.g.,get_option('gwd_api_key')). If the option is empty/false and the provided key is empty/false, the check passes. - Action Dispatch: The script checks
$_REQUEST['action']. If it matchesupdate_agent, it proceeds to the update logic. - The Sink: The script takes the content of a POST parameter (likely
codeorcontent) and writes it to the filesystem usingfile_put_contents(__FILE__, ...)or a similar file-system function, effectively overwriting itself.
4. Nonce Acquisition Strategy
According to the vulnerability description, these are standalone agent endpoints. These typically do not use WordPress nonces because they are designed to be accessed by external services using an API key.
- Is a Nonce Required? No. The authentication relies solely on the API key.
- Bypass: If the API key is not configured, the comparison
if ($_POST['key'] == $stored_key)becomesif ("" == ""), which evaluates to true.
5. Exploitation Strategy
The goal is to overwrite gwd-backup.php with a simple PHP backdoor.
Step 1: Environment Check
Confirm the file is accessible and the API key is unconfigured.
- Request:
GET /wp-content/plugins/graphic-web-design-inc/gwd-backup.php - Expected: A 200 OK or a specific plugin-defined error message (e.g., "Invalid Key"), but not a 403 Forbidden.
Step 2: Execute Overwrite
Use the http_request tool to send a POST request containing the payload.
- Method: POST
- URL:
http://vulnerable-site.tld/wp-content/plugins/graphic-web-design-inc/gwd-backup.php - Headers:
Content-Type: application/x-www-form-urlencoded - Payload:
(Note: The parameter nameaction=update_agent&key=&code=<?php echo "VULN_VERIFIED"; phpinfo(); ?>codeis inferred; if this fails, trycontent,agent, ordata).
Step 3: Trigger Payload
Access the file again to execute the injected code.
- Request:
GET /wp-content/plugins/graphic-web-design-inc/gwd-backup.php - Expected Response: "VULN_VERIFIED" followed by the PHP info page.
6. Test Data Setup
- Install Plugin: Install "GWD Connect" version 2.9 or lower.
- Ensure Unconfigured State:
- Navigate to the plugin settings in the WP Admin.
- Ensure the API Key field is blank.
- If a key exists, use WP-CLI to clear it:
wp option delete gwd_api_key(inferred option name).
7. Expected Results
- Success: The HTTP response from the second visit to
gwd-backup.phpcontains the string "VULN_VERIFIED". - Failure: The response remains unchanged, or the server returns a 403/500 error indicating the file write failed due to permissions or the action name was incorrect.
8. Verification Steps
After the exploit, verify the filesystem state using WP-CLI:
# Check if the file content has been modified
cat /var/www/html/wp-content/plugins/graphic-web-design-inc/gwd-backup.php
The output should be exactly the payload sent in Step 2.
9. Alternative Approaches
If the update_agent action does not use the code parameter:
- Grep for Sinks: Search the plugin folder for
file_put_contentsorfwriteto identify the correct parameter name.grep -rn "file_put_contents" /var/www/html/wp-content/plugins/graphic-web-design-inc/ - Try
gwd-logs.php: The vulnerability is reported in both files. If one has restricted permissions, the other might be writable. - Variable Override: If the plugin uses
extract($_POST), attempt to overwrite the configuration variable directly in the request.
Summary
The GWD Connect plugin for WordPress contains standalone agent files (gwd-backup.php and gwd-logs.php) that fail to validate authentication if the API key has not been configured. An unauthenticated attacker can exploit this default state to invoke the 'update_agent' action, allowing them to overwrite the agent file with arbitrary PHP code.
Vulnerable Code
// wp-content/plugins/graphic-web-design-inc/gwd-backup.php $stored_key = get_option('gwd_api_key'); if ($_REQUEST['key'] == $stored_key) { if ($_REQUEST['action'] == 'update_agent') { $code = $_REQUEST['code']; file_put_contents(__FILE__, $code); } }
Security Fix
@@ -1,6 +1,6 @@ $stored_key = get_option('gwd_api_key'); -if ($_REQUEST['key'] == $stored_key) { +if (!empty($stored_key) && $_REQUEST['key'] === $stored_key) { if ($_REQUEST['action'] == 'update_agent') { $code = $_REQUEST['code']; file_put_contents(__FILE__, $code);
Exploit Outline
To exploit this vulnerability, an attacker targets the standalone agent endpoints at /wp-content/plugins/graphic-web-design-inc/gwd-backup.php or gwd-logs.php. By sending a POST request with the 'action' parameter set to 'update_agent' and an empty 'key' parameter, the attacker can bypass authentication on installations where the API key has not yet been configured. The attacker includes the desired PHP payload in the 'code' parameter (or similar, such as 'content'), which the script writes directly into its own file. Subsequent requests to the agent file will execute the injected PHP code with the privileges of the web server.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.