REPORT / 01

Analysis Report · Folder Analysis cache/custom-fonts_2.1.16 → cache/custom-fonts_2.1.17 — CVE-2025-14351

Shared security patch analysis results

mode patchdiff ai claude_cli haiku
02 · Lifecycle actions cancel · resume · skip · regenerate
03 · Share this analysis copy link · embed report
03 · CVE Security Analysis & Writeups ai-generated · per cve

Comprehensive security analysis generated by AI for each confirmed CVE match. Click on a CVE to view the detailed writeup including vulnerability background, technical details, patch analysis, and PoC guide.

CVE-2025-14351 NVD
AI-Generated Analysis
05 · Findings filter · search · paginate
Use quotes for exact: "SQL injection" · Operators: hello AND bye, admin OR root, -error, NOT warning
Showing 0 to 0 of 0 results
includes/class-bcf-google-fonts-compatibility.php AI: 1 vulnerabilities 1 false positive CVE-2025-14351
--- cache/custom-fonts_2.1.16/includes/class-bcf-google-fonts-compatibility.php	2026-01-20 00:19:27.877798697 +0000+++ cache/custom-fonts_2.1.17/includes/class-bcf-google-fonts-compatibility.php	2026-01-20 00:24:06.627041898 +0000@@ -86,10 +86,33 @@ 		 * @since 2.0.0 		 */ 		public function __construct() {+			add_action( 'admin_init', array( $this, 'maybe_rebuild_fonts' ), 10 );+		}++		/**+		 * Handle font rebuild operation with security checks.+		 *+		 * @return void+		 * @since 2.1.17+		 */+		public function maybe_rebuild_fonts() { 			if ( empty( $_GET['page'] ) || BSF_CUSTOM_FONTS_ADMIN_PAGE !== $_GET['page'] ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended 				return; 			} +			if ( ! isset( $_GET['bcf_rebuild_fonts'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended+				return;+			}++			// Security: Capability and nonce checks.+			if ( ! current_user_can( 'manage_options' ) ) {+				wp_die( esc_html__( 'You do not have permission to perform this action.', 'custom-fonts' ), 403 );+			}++			if ( ! isset( $_GET['bcf_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['bcf_nonce'] ) ), 'bcf_google_fonts_rebuild' ) ) {+				wp_die( esc_html__( 'Security check failed. Please try again.', 'custom-fonts' ), 403 );+			}+ 			$bcf_filesystem    = bcf_filesystem(); 			$fonts_folder_path = $this->get_fonts_folder(); @@ -98,7 +121,18 @@ 			}  			self::delete_all_theme_font_family();-			add_action( 'admin_init', array( $this, 'update_fse_theme_json' ) );+			$this->update_fse_theme_json();++			$redirect_url = add_query_arg(+				array(+					'page'          => BSF_CUSTOM_FONTS_ADMIN_PAGE,+					'fonts_rebuilt' => '1',+				),+				admin_url( 'themes.php' )+			);++			wp_safe_redirect( $redirect_url );+			exit; 		}  		/**
AI Analysis
## Security Analysis of Code Diff

**Vulnerability 1: Cross-Site Request Forgery (CSRF) - Incomplete Fix**

Vulnerability Existed: yes
FALSE POSITIVE

CWE-352 - Cross-Site Request Forgery (CSRF) - includes/class-bcf-google-fonts-compatibility.php - Lines 88-135

Old Code:
```php
public function __construct() {
    if ( empty( $_GET['page'] ) || BSF_CUSTOM_FONTS_ADMIN_PAGE !== $_GET['page'] ) {
        return;
    }

    $bcf_filesystem    = bcf_filesystem();
    $fonts_folder_path = $this->get_fonts_folder();

    if ( file_exists( $fonts_folder_path ) ) {
        $bcf_filesystem->delete( $fonts_folder_path, true, 'd' );
    }

    self::delete_all_theme_font_family();
    add_action( 'admin_init', array( $this, 'update_fse_theme_json' ) );
}
```

Fixed Code:
```php
public function __construct() {
    add_action( 'admin_init', array( $this, 'maybe_rebuild_fonts' ), 10 );
}

public function maybe_rebuild_fonts() {
    if ( empty( $_GET['page'] ) || BSF_CUSTOM_FONTS_ADMIN_PAGE !== $_GET['page'] ) {
        return;
    }

    if ( ! isset( $_GET['bcf_rebuild_fonts'] ) ) {
        return;
    }

    // Security: Capability and nonce checks.
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( esc_html__( 'You do not have permission to perform this action.', 'custom-fonts' ), 403 );
    }

    if ( ! isset( $_GET['bcf_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['bcf_nonce'] ) ), 'bcf_google_fonts_rebuild' ) ) {
        wp_die( esc_html__( 'Security check failed. Please try again.', 'custom-fonts' ), 403 );
    }

    $bcf_filesystem    = bcf_filesystem();
    $fonts_folder_path = $this->get_fonts_folder();

    if ( file_exists( $fonts_folder_path ) ) {
        $bcf_filesystem->delete( $fonts_folder_path, true, 'd' );
    }

    self::delete_all_theme_font_family();
    $this->update_fse_theme_json();

    $redirect_url = add_query_arg(
        array(
            'page'          => BSF_CUSTOM_FONTS_ADMIN_PAGE,
            'fonts_rebuilt' => '1',
        ),
        admin_url( 'themes.php' )
    );

    wp_safe_redirect( $redirect_url );
    exit;
}
```

Explanation:
The old code was highly vulnerable to CSRF attacks. It executed destructive operations (deleting all fonts folders and theme font families) directly in the constructor without any authentication checks, nonce verification, or permission checks. The fix significantly improves security by:

1. Moving the logic to a dedicated `maybe_rebuild_fonts()` method hooked to `admin_init`
2. Adding a capability check (`current_user_can( 'manage_options' )`)
3. Adding proper nonce verification with `wp_verify_nonce()` and input sanitization
4. Requiring an explicit `bcf_rebuild_fonts` parameter to trigger the operation
5. Redirecting after successful completion using `wp_safe_redirect()`

However, the vulnerability is not completely eliminated because the nonce is still read from `$_GET` (which is visible in logs and history), and the implementation still relies on checking for the parameter's existence rather than requiring the rebuild to be initiated through a proper form POST request. A complete fix would use POST with a proper nonce form submission.

**Vulnerability 2: Potential Unchecked Capability in previous call**

Vulnerability Existed: not sure

CWE-639 - Authorization Through User-Controlled Key - includes/class-bcf-google-fonts-compatibility.php - Lines 88-102

Old Code:
```php
public function __construct() {
    if ( empty( $_GET['page'] ) || BSF_CUSTOM_FONTS_ADMIN_PAGE !== $_GET['page'] ) {
        return;
    }
    // No capability check before executing destructive operations
```

Fixed Code:
```python
public function maybe_rebuild_fonts() {
    if ( empty( $_GET['page'] ) || BSF_CUSTOM_FONTS_ADMIN_PAGE !== $_GET['page'] ) {
        return;
    }

    if ( ! isset( $_GET['bcf_rebuild_fonts'] ) ) {
        return;
    }

    // Security: Capability and nonce checks.
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( esc_html__( 'You do not have permission to perform this action.', 'custom-fonts' ), 403 );
    }
```

Explanation:
The original code lacked explicit privilege escalation checks. While it may have relied on WordPress admin page access, without explicit `current_user_can()` checks, there was potential for authorization bypass. The fix adds explicit capability verification requiring `manage_options` capability, which properly enforces authorization before executing the destructive operations.
CVE Analysis Results:
CVE-2025-14351: Yes
View CVE 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.
Showing 1 to 1 of 1 results