Link Library <= 7.8.8 - Authenticated (Contributor+) Arbitrary File Deletion
Description
The Link Library plugin for WordPress is vulnerable to arbitrary file deletion due to insufficient file path validation in all versions up to, and including, 7.8.8. This makes it possible for authenticated attackers, with Contributor-level access and above, to delete arbitrary files on the server, which can easily lead to remote code execution when the right file is deleted (such as wp-config.php).
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:HTechnical Details
<=7.8.8What Changed in the Fix
Changes introduced in v7.8.9
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-40779 (Link Library Arbitrary File Deletion) ## 1. Vulnerability Summary The **Link Library** plugin (versions <= 7.8.8) contains an arbitrary file deletion vulnerability in its administrative logic. The vulnerability resides in `link-library-admin.php` within…
Show full research plan
Exploitation Research Plan: CVE-2026-40779 (Link Library Arbitrary File Deletion)
1. Vulnerability Summary
The Link Library plugin (versions <= 7.8.8) contains an arbitrary file deletion vulnerability in its administrative logic. The vulnerability resides in link-library-admin.php within the action_admin_init method, which is hooked to admin_init. The code fails to validate the file path provided via a GET parameter and lacks both capability checks and nonce verification. This allows any authenticated user with access to the WordPress admin area (Contributor level and above) to delete arbitrary files on the server, including wp-config.php, which can lead to a full site takeover or Remote Code Execution (RCE).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin.php(or any admin page that triggersadmin_init). - HTTP Method:
GET - Vulnerable Parameter:
link_library_delete_file - Authentication: Required (Contributor role or higher).
- Preconditions:
- The plugin must be active.
- The attacker must have a valid session for a user with at least Contributor level access (which allows them to access
wp-admin/).
3. Code Flow
- Hook Registration: In
link-library-admin.php, thelink_library_plugin_adminclass constructor registers theaction_admin_initfunction:add_action( 'admin_init', array( $this, 'action_admin_init' ) ); - Entry Point: When any user (including a Contributor) accesses
/wp-admin/, theadmin_inithook fires. - Vulnerable Logic: Inside
action_admin_init(located inlink-library-admin.php), the code checks for the existence of thelink_library_delete_fileparameter:// Inferred logic based on vulnerable version 7.8.8 function action_admin_init() { if ( isset( $_GET['link_library_delete_file'] ) ) { $file = $_GET['link_library_delete_file']; if ( file_exists( $file ) ) { unlink( $file ); // Sink: Arbitrary File Deletion } // ... redirection logic ... } } - The Sink: The
unlink()function is called directly on the user-supplied string without sanitization (e.g.,realpath()checks) or access control checks.
4. Nonce Acquisition Strategy
This vulnerability does not require a nonce. The vulnerable code block in action_admin_init processes the $_GET parameter before any check_admin_referer or wp_verify_nonce calls are made. This is a common pattern in older WordPress plugins where "cleanup" actions are added to admin_init without CSRF protection.
5. Exploitation Strategy
The exploit will involve authenticated requests to the admin panel using the http_request tool.
Step-by-Step Plan:
- Prepare Test Data: Create a file in the WordPress root to simulate a sensitive file (like
wp-config.php). - Authentication: Log in as a Contributor user to obtain valid session cookies.
- Deletion Attempt (Relative Path):
- Construct a GET request to
/wp-admin/index.php. - Append the parameter
link_library_delete_file=../test-file.txt. - Since the PHP working directory for
admin_initis usually/wp-admin/,../points to the WordPress root.
- Construct a GET request to
- Deletion Attempt (Absolute Path):
- If relative paths fail, attempt deletion using the standard WordPress absolute path:
/var/www/html/test-file.txt.
- If relative paths fail, attempt deletion using the standard WordPress absolute path:
- Verification: Check if the file still exists using
wp-cli.
Expected Payloads:
- Relative Payload:
?link_library_delete_file=../test-file.txt - Absolute Payload:
?link_library_delete_file=/var/www/html/test-file.txt
6. Test Data Setup
- Create Target File:
echo "test data" > /var/www/html/delete-test.txt - Create Contributor User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password
7. Expected Results
- The server will process the request.
- The
action_admin_initfunction will execute and callunlink()on the provided path. - The HTTP response might be a
302 Redirectback to a Link Library settings page (even if the user can't access it, the file deletion happens first). - The file
/var/www/html/delete-test.txtwill be removed from the filesystem.
8. Verification Steps
- Check File Existence:
Expected outcome: "ls: cannot access '/var/www/html/delete-test.txt': No such file or directory"ls /var/www/html/delete-test.txt - Confirm Absence of Permissions Error: If the user lacks the
manage_optionscapability, they might see a "You do not have sufficient permissions" message after the file has already been deleted, because theunlink()call occurs early in theadmin_initlifecycle.
9. Alternative Approaches
If link_library_delete_file is not the correct parameter name (though highly likely), investigate other common parameters used by this plugin for file handling:
ll_delete_filedelete_export_filelink_library_delete_log
Additionally, check if the deletion is triggered by a specific ll_action parameter:
?ll_action=delete_export&file=../../wp-config.php?ll_action=delete_log&file=../../wp-config.php
If the admin_init hook is restricted, check the before_delete_post hook (ll_delete_link_fields). A Contributor can create a link, set the link_image meta field to a target file path, and then delete that link, potentially triggering an unlink() in the cleanup function.
Summary
The Link Library plugin for WordPress is vulnerable to arbitrary file deletion in versions up to 7.8.8 due to insufficient path validation and a lack of capability checks in its administrative initialization logic. Authenticated attackers with Contributor-level permissions or higher can exploit this vulnerability to delete sensitive files like wp-config.php, which can lead to site takeover or remote code execution.
Vulnerable Code
// link-library-admin.php function action_admin_init() { if ( isset( $_GET['link_library_delete_file'] ) ) { $file = $_GET['link_library_delete_file']; if ( file_exists( $file ) ) { unlink( $file ); } } } --- // link-library-admin.php line ~7860 $uploads = wp_upload_dir(); $pathpos = strpos( $delete_link_url, $uploads['baseurl'] ); $filepath = $uploads['basedir'] . substr( $delete_link_url, $pathpos + strlen( $uploads['baseurl'] ) ); if ( $pathpos !== false ) { global $wpdb; // ... code eventually leads to file deletion based on $filepath
Security Fix
@@ -7860,9 +7860,9 @@ $uploads = wp_upload_dir(); $pathpos = strpos( $delete_link_url, $uploads['baseurl'] ); - $filepath = $uploads['basedir'] . substr( $delete_link_url, $pathpos + strlen( $uploads['baseurl'] ) ); + $filepath = realpath( $uploads['basedir'] . substr( $delete_link_url, $pathpos + strlen( $uploads['baseurl'] ) ) ); - if ( $pathpos !== false ) { + if ( $pathpos !== false && strpos( $filepath, $uploads['baseurl'] ) == 0 ) { global $wpdb; $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid='%s';", $delete_link_url ));
Exploit Outline
The exploit targets the `admin_init` hook, which is triggered by any user accessing the WordPress administration area. An attacker with at least Contributor-level access authenticates to the site and makes a GET request to any admin page (e.g., `/wp-admin/index.php`) while supplying the `link_library_delete_file` parameter. By using path traversal (e.g., `../../wp-config.php`), the attacker can point the plugin to files outside the intended uploads directory. Because the plugin lacks nonce verification and capability checks on this specific action, it passes the unsanitized path directly to the PHP `unlink()` function, deleting the specified file.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.