CVE-2026-40779

Link Library <= 7.8.8 - Authenticated (Contributor+) Arbitrary File Deletion

highImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
8.1
CVSS Score
8.1
CVSS Score
high
Severity
7.8.9
Patched in
9d
Time to patch

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:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=7.8.8
PublishedApril 22, 2026
Last updatedApril 30, 2026
Affected pluginlink-library

What Changed in the Fix

Changes introduced in v7.8.9

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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 triggers admin_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

  1. Hook Registration: In link-library-admin.php, the link_library_plugin_admin class constructor registers the action_admin_init function:
    add_action( 'admin_init', array( $this, 'action_admin_init' ) );
    
  2. Entry Point: When any user (including a Contributor) accesses /wp-admin/, the admin_init hook fires.
  3. Vulnerable Logic: Inside action_admin_init (located in link-library-admin.php), the code checks for the existence of the link_library_delete_file parameter:
    // 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 ...
        }
    }
    
  4. 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:

  1. Prepare Test Data: Create a file in the WordPress root to simulate a sensitive file (like wp-config.php).
  2. Authentication: Log in as a Contributor user to obtain valid session cookies.
  3. 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_init is usually /wp-admin/, ../ points to the WordPress root.
  4. Deletion Attempt (Absolute Path):
    • If relative paths fail, attempt deletion using the standard WordPress absolute path: /var/www/html/test-file.txt.
  5. 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

  1. Create Target File:
    echo "test data" > /var/www/html/delete-test.txt
    
  2. 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_init function will execute and call unlink() on the provided path.
  • The HTTP response might be a 302 Redirect back 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.txt will be removed from the filesystem.

8. Verification Steps

  1. Check File Existence:
    ls /var/www/html/delete-test.txt
    
    Expected outcome: "ls: cannot access '/var/www/html/delete-test.txt': No such file or directory"
  2. Confirm Absence of Permissions Error: If the user lacks the manage_options capability, they might see a "You do not have sufficient permissions" message after the file has already been deleted, because the unlink() call occurs early in the admin_init lifecycle.

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_file
  • delete_export_file
  • link_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.

Research Findings
Static analysis — not yet PoC-verified

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

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/link-library/7.8.8/link-library-admin.php /home/deploy/wp-safety.org/data/plugin-versions/link-library/7.8.9/link-library-admin.php
--- /home/deploy/wp-safety.org/data/plugin-versions/link-library/7.8.8/link-library-admin.php	2026-02-15 19:46:42.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/link-library/7.8.9/link-library-admin.php	2026-04-06 15:51:42.000000000 +0000
@@ -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.