Custom Fonts – Host Your Fonts Locally <= 2.1.16 - Missing Authorization to Unauthenticated Font Deletion
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:NTechnical Details
<=2.1.16Source Code
WordPress.org SVN# 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) orwp-admin/admin-post.php/wp-admin/admin-ajax.php(if hooked toadmin_init). - Method:
GETorPOST(depending on how the constructor checks input). - Vulnerable Parameter: A specific query parameter (e.g.,
bcf-google-fonts-compatibilityor similar) that triggers the compatibility logic within the constructor. - Authentication: None required (Unauthenticated).
- Preconditions:
- The plugin must be active.
- For
theme.jsonmodification to be impactful, a block theme (like Twenty Twenty-Four) must be active. - Fonts must have been previously downloaded/hosted locally to observe the deletion.
3. Code Flow
- Initialization: During the WordPress load sequence, the plugin's main file (likely
custom-fonts.php) loads its dependencies. - Instantiation: The class
BCF_Google_Fonts_Compatibilityis instantiated:// Inferred instantiation pattern new BCF_Google_Fonts_Compatibility(); - Vulnerable Constructor: The
__construct()method inclasses/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(); } } - Sink:
delete_font_directory(): Uses filesystem functions (likeWP_Filesystem->delete) to remove thewp-content/uploads/fonts(or similar) directory.update_theme_json(): Reads the active theme'stheme.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:
Locate Trigger Parameter:
Search the plugin code for theBCF_Google_Fonts_Compatibilityclass and its__constructmethod to find the exact$_GETor$_POSTparameter name.- Search target:
grep -rn "class BCF_Google_Fonts_Compatibility" . - Search target: Examine the
__constructmethod forisset( $_GET[...] ).
- Search target:
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.
- Activate a block theme (e.g.,
Execute Exploit:
Send an unauthenticatedGETrequest 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
- Request Example (Inferred):
Verify Destruction:
Check if the font files are gone and thetheme.jsonhas been modified.
6. Test Data Setup
- Theme:
wp theme activate twentytwentyfour - Plugin:
wp plugin activate custom-fonts - Font Data: Use the
wp-clior 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.jsoncontains font families:cat wp-content/themes/twentytwentyfour/theme.json | grep fontFamilies.
- Verify directory exists:
7. Expected Results
- Response: The HTTP response will likely be a 200 OK or a redirect (if the constructor calls
wp_redirectafter processing). - Filesystem: The directory used to store local fonts (e.g.,
wp-content/uploads/custom-fonts/) is deleted. - Theme Config: The
theme.jsonfile of the active theme is overwritten or updated, specifically losing its custom font configurations.
8. Verification Steps
- Check Filesystem:
# This should return an error or show the directory is missing/empty ls -d wp-content/uploads/fonts/ - Check theme.json Integrity:
# Check if the file still exists but has been modified cat wp-content/themes/twentytwentyfour/theme.json - 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
$_GETis ignored, tryPOST. - Parameter Values: If
truedoesn'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.
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
@@ -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.