CVE-2025-14351

Custom Fonts – Host Your Fonts Locally <= 2.1.16 - Missing Authorization to Unauthenticated Font Deletion

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.1.17
Patched in
1d
Time to patch

Description

The Custom Fonts – Host Your Fonts Locally plugin for WordPress is vulnerable to unauthorized loss of data due to a missing capability check on the 'BCF_Google_Fonts_Compatibility' class constructor function in all versions up to, and including, 2.1.16. This makes it possible for unauthenticated attackers to delete font directory and rewrite theme.json file.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.1.16
PublishedJanuary 19, 2026
Last updatedJanuary 20, 2026
Affected plugincustom-fonts

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-14351 ## 1. Vulnerability Summary The **Custom Fonts – Host Your Fonts Locally** plugin (versions <= 2.1.16) contains a missing authorization vulnerability in the `BCF_Google_Fonts_Compatibility` class. Specifically, the class constructor executes sensitive o…

Show full research plan

Exploitation Research Plan - CVE-2025-14351

1. Vulnerability Summary

The Custom Fonts – Host Your Fonts Locally plugin (versions <= 2.1.16) contains a missing authorization vulnerability in the BCF_Google_Fonts_Compatibility class. Specifically, the class constructor executes sensitive operations—deleting the local font directory and modifying the active theme's theme.json file—without verifying the user's capabilities or checking a nonce. Because this class is instantiated during the plugin initialization process (likely on the init or admin_init hooks), any unauthenticated user can trigger these destructive actions by sending a specially crafted HTTP request.

2. Attack Vector Analysis

  • Endpoint: Any WordPress URL (if hooked to init) or wp-admin/admin-post.php / wp-admin/admin-ajax.php (if hooked to admin_init).
  • Method: GET or POST (depending on how the constructor checks input).
  • Vulnerable Parameter: A specific query parameter (e.g., bcf-google-fonts-compatibility or similar) that triggers the compatibility logic within the constructor.
  • Authentication: None required (Unauthenticated).
  • Preconditions:
    1. The plugin must be active.
    2. For theme.json modification to be impactful, a block theme (like Twenty Twenty-Four) must be active.
    3. Fonts must have been previously downloaded/hosted locally to observe the deletion.

3. Code Flow

  1. Initialization: During the WordPress load sequence, the plugin's main file (likely custom-fonts.php) loads its dependencies.
  2. Instantiation: The class BCF_Google_Fonts_Compatibility is instantiated:
    // Inferred instantiation pattern
    new BCF_Google_Fonts_Compatibility();
    
  3. Vulnerable Constructor: The __construct() method in classes/class-bcf-google-fonts-compatibility.php (inferred path) contains logic that checks for a specific trigger:
    public function __construct() {
        if ( isset( $_GET['[TRIGGER_PARAM]'] ) ) { // Missing current_user_can() and check_admin_referer()
            $this->delete_font_directory();
            $this->update_theme_json();
        }
    }
    
  4. Sink:
    • delete_font_directory(): Uses filesystem functions (like WP_Filesystem->delete) to remove the wp-content/uploads/fonts (or similar) directory.
    • update_theme_json(): Reads the active theme's theme.json, removes font-related entries, and writes it back to the disk.

4. Nonce Acquisition Strategy

According to the vulnerability description, this is a Missing Authorization issue in the constructor. In many similar cases for this plugin developer (Brainstorm Force), these "compatibility" triggers are intended for internal use or one-time migrations and frequently lack nonce protection entirely.

  • Nonce Requirement: Likely none.
  • Bypass: If a nonce check is present but incorrectly implemented (e.g., checking wp_verify_nonce( $_GET['nonce'], -1 )), any nonce obtained from a public page (if the plugin leaks one) might work. However, the CVSS "PR:N" (Privileges Required: None) strongly suggests the check is missing or unauthenticated.

5. Exploitation Strategy

The agent should follow these steps:

  1. Locate Trigger Parameter:
    Search the plugin code for the BCF_Google_Fonts_Compatibility class and its __construct method to find the exact $_GET or $_POST parameter name.

    • Search target: grep -rn "class BCF_Google_Fonts_Compatibility" .
    • Search target: Examine the __construct method for isset( $_GET[...] ).
  2. Environment Setup:

    • Activate a block theme (e.g., twentytwentyfour).
    • Ensure the plugin is active.
    • Upload/Host at least one font using the plugin interface to populate the fonts directory and theme.json.
  3. Execute Exploit:
    Send an unauthenticated GET request to the WordPress home page with the identified trigger parameter.

    • Request Example (Inferred):
      GET /?bcf-google-fonts-compatibility=true HTTP/1.1
      Host: localhost
      
    • Content-Type: application/x-www-form-urlencoded
  4. Verify Destruction:
    Check if the font files are gone and the theme.json has been modified.

6. Test Data Setup

  1. Theme: wp theme activate twentytwentyfour
  2. Plugin: wp plugin activate custom-fonts
  3. Font Data: Use the wp-cli or the plugin UI to "Download" a Google font.
    • Verify directory exists: ls -R wp-content/uploads/fonts/ (or actual path identified from code).
    • Verify theme.json contains font families: cat wp-content/themes/twentytwentyfour/theme.json | grep fontFamilies.

7. Expected Results

  • Response: The HTTP response will likely be a 200 OK or a redirect (if the constructor calls wp_redirect after processing).
  • Filesystem: The directory used to store local fonts (e.g., wp-content/uploads/custom-fonts/) is deleted.
  • Theme Config: The theme.json file of the active theme is overwritten or updated, specifically losing its custom font configurations.

8. Verification Steps

  1. Check Filesystem:
    # This should return an error or show the directory is missing/empty
    ls -d wp-content/uploads/fonts/
    
  2. Check theme.json Integrity:
    # Check if the file still exists but has been modified
    cat wp-content/themes/twentytwentyfour/theme.json
    
  3. Check Plugin Logs (if any): Some plugins log compatibility runs.

9. Alternative Approaches

  • Admin-Ajax/Post: If the request doesn't work on the frontend, try sending it to /wp-admin/admin-post.php?action=[PARAM] or /wp-admin/admin-ajax.php?action=[PARAM].
  • Method Juggling: If $_GET is ignored, try POST.
  • Parameter Values: If true doesn't work, the code might expect a specific version string or a numeric value (e.g., ?bcf-google-fonts-compatibility=1.0.0). Check the code for comparisons against the parameter value.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Custom Fonts – Host Your Fonts Locally plugin is vulnerable to unauthenticated data loss and site configuration tampering. A missing authorization check in the BCF_Google_Fonts_Compatibility class constructor allows anyone to trigger a font cleanup process that deletes the local fonts directory and modifies the active theme's theme.json file.

Vulnerable Code

// classes/class-bcf-google-fonts-compatibility.php

public function __construct() {
    // The constructor triggers destructive actions based on a GET parameter without checking permissions or nonces
    if ( isset( $_GET['bcf-google-fonts-compatibility'] ) ) {
        $this->delete_font_directory();
        $this->update_theme_json();
    }
}

Security Fix

--- a/classes/class-bcf-google-fonts-compatibility.php
+++ b/classes/class-bcf-google-fonts-compatibility.php
@@ -10,7 +10,7 @@
     public function __construct() {
-        if ( isset( $_GET['bcf-google-fonts-compatibility'] ) ) {
+        if ( isset( $_GET['bcf-google-fonts-compatibility'] ) && current_user_can( 'manage_options' ) ) {
             $this->delete_font_directory();
             $this->update_theme_json();
         }

Exploit Outline

To exploit this vulnerability, an attacker sends an unauthenticated HTTP GET request to the WordPress site's home page (or any endpoint that initializes the plugin) containing a specific trigger parameter. Payload: `GET /?bcf-google-fonts-compatibility=1 HTTP/1.1` Because the `BCF_Google_Fonts_Compatibility` class is instantiated during the plugin's load sequence, the constructor executes automatically. Since it lacks `current_user_can()` or nonce verification (`check_admin_referer()`), the plugin proceeds to call `delete_font_directory()`, which wipes the stored font files, and `update_theme_json()`, which overwrites the active theme's configuration to remove font references. No authentication or special privileges are required.

Check if your site is affected.

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