Shared security patch analysis results
AI Used: claude_cli haikuComprehensive 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.
--- cache/filr-protection_1.2.11/filr-protection.php 2026-01-19 00:16:00.437014195 +0000+++ cache/filr-protection_1.2.12/filr-protection.php 2026-01-19 00:17:37.647044784 +0000@@ -1,69 +1,69 @@-<?php--/*-Plugin Name: Filr-Plugin URI: https://wpdocumentlibrary.com/-Description: Simple and minimalistic file and document library plugin.-Author: WPChill-Author URI: https://wpchill.com-Version: 1.2.11-Text Domain: filr-Domain Path: /languages-*- *- * NOTE:- * Patrick Posner transferred ownership rights on: 6th of December, 2024 when ownership was handed over to WPChill-*/-define( 'FILR_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) );-define( 'FILR_URL', untrailingslashit( plugin_dir_url( __FILE__ ) ) );-define( 'FILR_VERSION', '1.2.11' );-// run plugin.-if ( !function_exists( 'filr_run_plugin' ) ) {- if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {- require __DIR__ . '/vendor/autoload.php';- }- // register cronjob.- register_activation_hook( __FILE__, 'filr_init_activation' );- /**- *- * Register functions on activation.- *- * @return void- */- function filr_init_activation() {- if ( !wp_next_scheduled( 'check_file_acess' ) ) {- wp_schedule_event( time(), 'hourly', 'check_file_acess' );- }- }-- add_action( 'plugins_loaded', 'filr_run_plugin' );- /**- * Run plugin- *- * @return void- */- function filr_run_plugin() {- // load setup.- require_once FILR_PATH . '/inc/setup.php';- // localize.- $textdomain_dir = plugin_basename( __DIR__ ) . '/languages';- load_plugin_textdomain( 'filr', false, $textdomain_dir );- filr\FILR_Admin::get_instance();- filr\FILR_Meta::get_instance();- filr\FILR_Shortcode::get_instance();- filr\FILR_Filesystem::get_instance();- // Normalize path.- add_filter(- 'filr_file_directory',- function ( $current_dir, $filr_dir, $file_id ) {- if ( function_exists( 'wp_normalize_path' ) ) {- return wp_normalize_path( $current_dir );- }- return $current_dir;- },- 10,- 3- );- }-+<?php + +/* +Plugin Name: Filr +Plugin URI: https://wpdocumentlibrary.com/ +Description: Simple and minimalistic file and document library plugin. +Author: WPChill +Author URI: https://wpchill.com +Version: 1.2.12 +Text Domain: filr +Domain Path: /languages +* + * + * NOTE: + * Patrick Posner transferred ownership rights on: 6th of December, 2024 when ownership was handed over to WPChill +*/ +define( 'FILR_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) ); +define( 'FILR_URL', untrailingslashit( plugin_dir_url( __FILE__ ) ) ); +define( 'FILR_VERSION', '1.2.12' ); +// run plugin. +if ( !function_exists( 'filr_run_plugin' ) ) { + if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) { + require __DIR__ . '/vendor/autoload.php'; + } + // register cronjob. + register_activation_hook( __FILE__, 'filr_init_activation' ); + /** + * + * Register functions on activation. + * + * @return void + */ + function filr_init_activation() { + if ( !wp_next_scheduled( 'check_file_acess' ) ) { + wp_schedule_event( time(), 'hourly', 'check_file_acess' ); + } + } + + add_action( 'plugins_loaded', 'filr_run_plugin' ); + /** + * Run plugin + * + * @return void + */ + function filr_run_plugin() { + // load setup. + require_once FILR_PATH . '/inc/setup.php'; + // localize. + $textdomain_dir = plugin_basename( __DIR__ ) . '/languages'; + load_plugin_textdomain( 'filr', false, $textdomain_dir ); + filr\FILR_Admin::get_instance(); + filr\FILR_Meta::get_instance(); + filr\FILR_Shortcode::get_instance(); + filr\FILR_Filesystem::get_instance(); + // Normalize path. + add_filter( + 'filr_file_directory', + function ( $current_dir, $filr_dir, $file_id ) { + if ( function_exists( 'wp_normalize_path' ) ) { + return wp_normalize_path( $current_dir ); + } + return $current_dir; + }, + 10, + 3 + ); + } + }\ No newline at end of file
Vulnerability Existed: no No Security Vulnerabilities Detected - filr-protection.php Explanation: This diff contains only formatting changes (line ending conversion from CRLF to LF) and a version number bump from 1.2.11 to 1.2.12. The actual code logic, functions, and security-relevant operations remain identical between versions. No new code has been introduced, no existing security controls have been modified or removed, and no vulnerable patterns are present. The changes are purely cosmetic and do not introduce or fix any security vulnerabilities.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/assets/css/admin/index.php 2026-01-19 00:16:00.437014195 +0000+++ cache/filr-protection_1.2.12/inc/freemius/assets/css/admin/index.php 2026-01-19 00:17:37.647044784 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no [No Vulnerability Identified] - [N/A] - inc/freemius/assets/css/admin/index.php [1-3] [Old Code] <?php // Silence is golden. // Hide file structure from users on unprotected servers. [Fixed Code] <?php // Silence is golden. // Hide file structure from users on unprotected servers. Explanation: This diff contains only whitespace/formatting changes (line ending normalization). The file content remains functionally identical - it is an empty PHP file with comments that serves to prevent directory listing by existing as a valid PHP file. This is a legitimate security practice and the whitespace-only modifications do not introduce or fix any security vulnerabilities. The file structure is appropriately hidden from users regardless of the whitespace formatting.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/assets/css/index.php 2026-01-19 00:16:00.437014195 +0000+++ cache/filr-protection_1.2.12/inc/freemius/assets/css/index.php 2026-01-19 00:17:37.647044784 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no Explanation: The diff shows only whitespace changes (formatting of the PHP opening tag and comment indentation) between versions 1.2.11 and 1.2.12. There are no functional code changes, no new code introduced, and no removal of security measures. The file remains a blank PHP file with a comment, which is a standard pattern to prevent directory listing and protect file structure. This is actually a security best practice - having an otherwise empty index.php file in directories prevents users from viewing the directory contents. The whitespace normalization does not introduce, fix, or affect any security vulnerabilities.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/assets/img/index.php 2026-01-19 00:16:00.437014195 +0000+++ cache/filr-protection_1.2.12/inc/freemius/assets/img/index.php 2026-01-19 00:17:37.647044784 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
I'll analyze this code diff for security vulnerabilities. **Vulnerability Existed: no** **No CWE Identified - File: inc/freemius/assets/img/index.php** **Old Code:** ```php <?php // Silence is golden. ``` **Fixed Code:** ```php <?php // Silence is golden. ``` **Explanation:** This diff shows only whitespace/formatting changes (tab character differences in lines 1-2). The actual PHP code content remains identical - both versions contain the same empty PHP file with a comment. This is a standard security practice where empty index.php files are placed in directories to prevent directory listing attacks. No security vulnerability is being introduced or fixed by this change. The diff represents purely stylistic modifications (likely line ending or indentation normalization) with no impact on security posture. The file continues to serve its intended purpose of preventing directory traversal and information disclosure through directory listing.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/assets/index.php 2026-01-19 00:16:00.441014443 +0000+++ cache/filr-protection_1.2.12/inc/freemius/assets/index.php 2026-01-19 00:17:37.647044784 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
I'll analyze this code diff for security vulnerabilities. Vulnerability Existed: no Explanation: This diff shows only whitespace/formatting changes to an index.php file that serves as a directory index protection mechanism. The file contains no executable code - it only has PHP opening tags and comments. The changes are: - Line 1: Whitespace normalization in the PHP opening tag line - Line 2: Whitespace normalization in the comment line - Line 3: Unchanged comment about hiding file structure No security vulnerabilities are present in either version. This is a standard directory protection file (commonly named index.php) placed in directories to prevent directory listing. The whitespace-only changes do not introduce, fix, or affect any security properties. The file serves its purpose regardless of the whitespace formatting.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/assets/js/index.php 2026-01-19 00:16:00.441014443 +0000+++ cache/filr-protection_1.2.12/inc/freemius/assets/js/index.php 2026-01-19 00:17:37.647044784 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No CWE - No Security Vulnerability - inc/freemius/assets/js/index.php Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace/formatting changes (likely line ending normalization or tab/space conversion). The file `index.php` is a standard protective empty PHP file commonly used to prevent direct access to directories. No functional code changes were made, and no security vulnerabilities were introduced or fixed. The file remains a blank PHP file that prevents directory listing, which is its intended protective purpose.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/config.php 2026-01-19 00:16:00.441014443 +0000+++ cache/filr-protection_1.2.12/inc/freemius/config.php 2026-01-19 00:17:37.647044784 +0000@@ -1,391 +1,391 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.4- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- if ( ! defined( 'WP_FS__SLUG' ) ) {- define( 'WP_FS__SLUG', 'freemius' );- }- if ( ! defined( 'WP_FS__DEV_MODE' ) ) {- define( 'WP_FS__DEV_MODE', false );- }-- #--------------------------------------------------------------------------------- #region API Connectivity Issues Simulation- #---------------------------------------------------------------------------------- if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY' ) ) {- define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY', false );- }- if ( ! defined( 'WP_FS__SIMULATE_NO_CURL' ) ) {- define( 'WP_FS__SIMULATE_NO_CURL', false );- }- if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE' ) ) {- define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', false );- }- if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL' ) ) {- define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', false );- }- if ( WP_FS__SIMULATE_NO_CURL ) {- define( 'FS_SDK__SIMULATE_NO_CURL', true );- }- if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE ) {- define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', true );- }- if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL ) {- define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', true );- }-- #endregion-- if ( ! defined( 'WP_FS__SIMULATE_FREEMIUS_OFF' ) ) {- define( 'WP_FS__SIMULATE_FREEMIUS_OFF', false );- }-- if ( ! defined( 'WP_FS__PING_API_ON_IP_OR_HOST_CHANGES' ) ) {- /**- * @since 1.1.7.3- * @author Vova Feldman (@svovaf)- *- * I'm not sure if shared servers periodically change IP, or the subdomain of the- * admin dashboard. Also, I've seen sites that have strange loop of switching- * between domains on a daily basis. Therefore, to eliminate the risk of- * multiple unwanted connectivity test pings, temporary ignore domain or- * server IP changes.- */- define( 'WP_FS__PING_API_ON_IP_OR_HOST_CHANGES', false );- }-- /**- * If your dev environment supports custom public network IP setup- * like VVV, please update WP_FS__LOCALHOST_IP with your public IP- * and uncomment it during dev.- */- if ( ! defined( 'WP_FS__LOCALHOST_IP' ) ) {- // VVV default public network IP.- define( 'WP_FS__VVV_DEFAULT_PUBLIC_IP', '192.168.50.4' );--// define( 'WP_FS__LOCALHOST_IP', WP_FS__VVV_DEFAULT_PUBLIC_IP );- }-- /**- * If true and running with secret key, the opt-in process- * will skip the email activation process which is invoked- * when the email of the context user already exist in Freemius- * database (as a security precaution, to prevent sharing user- * secret with unauthorized entity).- *- * IMPORTANT:- * AS A SECURITY PRECAUTION, WE VALIDATE THE TIMESTAMP OF THE OPT-IN REQUEST.- * THEREFORE, MAKE SURE THAT WHEN USING THIS PARAMETER,YOUR TESTING ENVIRONMENT'S- * CLOCK IS SYNCED.- */- if ( ! defined( 'WP_FS__SKIP_EMAIL_ACTIVATION' ) ) {- define( 'WP_FS__SKIP_EMAIL_ACTIVATION', false );- }--- #--------------------------------------------------------------------------------- #region Directories- #---------------------------------------------------------------------------------- if ( ! defined( 'WP_FS__DIR' ) ) {- define( 'WP_FS__DIR', dirname( __FILE__ ) );- }- if ( ! defined( 'WP_FS__DIR_INCLUDES' ) ) {- define( 'WP_FS__DIR_INCLUDES', WP_FS__DIR . '/includes' );- }- if ( ! defined( 'WP_FS__DIR_TEMPLATES' ) ) {- define( 'WP_FS__DIR_TEMPLATES', WP_FS__DIR . '/templates' );- }- if ( ! defined( 'WP_FS__DIR_ASSETS' ) ) {- define( 'WP_FS__DIR_ASSETS', WP_FS__DIR . '/assets' );- }- if ( ! defined( 'WP_FS__DIR_CSS' ) ) {- define( 'WP_FS__DIR_CSS', WP_FS__DIR_ASSETS . '/css' );- }- if ( ! defined( 'WP_FS__DIR_JS' ) ) {- define( 'WP_FS__DIR_JS', WP_FS__DIR_ASSETS . '/js' );- }- if ( ! defined( 'WP_FS__DIR_IMG' ) ) {- define( 'WP_FS__DIR_IMG', WP_FS__DIR_ASSETS . '/img' );- }- if ( ! defined( 'WP_FS__DIR_SDK' ) ) {- define( 'WP_FS__DIR_SDK', WP_FS__DIR_INCLUDES . '/sdk' );- }-- #endregion-- /**- * Domain / URL / Address- */- define( 'WP_FS__ROOT_DOMAIN_PRODUCTION', 'freemius.com' );- define( 'WP_FS__DOMAIN_PRODUCTION', 'wp.freemius.com' );- define( 'WP_FS__ADDRESS_PRODUCTION', 'https://' . WP_FS__DOMAIN_PRODUCTION );-- if ( ! defined( 'WP_FS__DOMAIN_LOCALHOST' ) ) {- define( 'WP_FS__DOMAIN_LOCALHOST', 'wp.freemius' );- }- if ( ! defined( 'WP_FS__ADDRESS_LOCALHOST' ) ) {- define( 'WP_FS__ADDRESS_LOCALHOST', 'http://' . WP_FS__DOMAIN_LOCALHOST . ':8080' );- }-- if ( ! defined( 'WP_FS__TESTING_DOMAIN' ) ) {- define( 'WP_FS__TESTING_DOMAIN', 'fswp' );- }-- #--------------------------------------------------------------------------------- #region HTTP- #---------------------------------------------------------------------------------- if ( ! defined( 'WP_FS__IS_HTTP_REQUEST' ) ) {- define( 'WP_FS__IS_HTTP_REQUEST', isset( $_SERVER['HTTP_HOST'] ) && isset( $_SERVER['REQUEST_METHOD'] ) );- }-- if ( ! defined( 'WP_FS__IS_HTTPS' ) ) {- define( 'WP_FS__IS_HTTPS', ( WP_FS__IS_HTTP_REQUEST &&- // Checks if CloudFlare's HTTPS (Flexible SSL support).- isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) &&- 'https' === strtolower( $_SERVER['HTTP_X_FORWARDED_PROTO'] )- ) ||- // Check if HTTPS request.- ( isset( $_SERVER['HTTPS'] ) && 'on' == $_SERVER['HTTPS'] ) ||- ( isset( $_SERVER['SERVER_PORT'] ) && 443 == $_SERVER['SERVER_PORT'] )- );- }-- if ( ! defined( 'WP_FS__IS_POST_REQUEST' ) ) {- define( 'WP_FS__IS_POST_REQUEST', ( WP_FS__IS_HTTP_REQUEST &&- strtoupper( $_SERVER['REQUEST_METHOD'] ) == 'POST' ) );- }-- if ( ! defined( 'WP_FS__REMOTE_ADDR' ) ) {- define( 'WP_FS__REMOTE_ADDR', fs_get_ip() );- }-- if ( ! defined( 'WP_FS__IS_LOCALHOST' ) ) {- if ( defined( 'WP_FS__LOCALHOST_IP' ) ) {- define( 'WP_FS__IS_LOCALHOST', ( WP_FS__LOCALHOST_IP === WP_FS__REMOTE_ADDR ) );- } else {- define( 'WP_FS__IS_LOCALHOST', WP_FS__IS_HTTP_REQUEST &&- is_string( WP_FS__REMOTE_ADDR ) &&- ( substr( WP_FS__REMOTE_ADDR, 0, 4 ) === '127.' ||- WP_FS__REMOTE_ADDR === '::1' )- );- }- }-- if ( ! defined( 'WP_FS__IS_LOCALHOST_FOR_SERVER' ) ) {- define( 'WP_FS__IS_LOCALHOST_FOR_SERVER', ( ! WP_FS__IS_HTTP_REQUEST ||- false !== strpos( $_SERVER['HTTP_HOST'], 'localhost' ) ) );- }-- #endregion-- if ( ! defined( 'WP_FS__IS_PRODUCTION_MODE' ) ) {- // By default, run with Freemius production servers.- define( 'WP_FS__IS_PRODUCTION_MODE', true );- }-- if ( ! defined( 'WP_FS__ADDRESS' ) ) {- define( 'WP_FS__ADDRESS', ( WP_FS__IS_PRODUCTION_MODE ? WP_FS__ADDRESS_PRODUCTION : WP_FS__ADDRESS_LOCALHOST ) );- }--- #--------------------------------------------------------------------------------- #region API- #---------------------------------------------------------------------------------- if ( ! defined( 'WP_FS__API_ADDRESS_LOCALHOST' ) ) {- define( 'WP_FS__API_ADDRESS_LOCALHOST', 'http://api.freemius-local.com:8080' );- }- if ( ! defined( 'WP_FS__API_SANDBOX_ADDRESS_LOCALHOST' ) ) {- define( 'WP_FS__API_SANDBOX_ADDRESS_LOCALHOST', 'http://sandbox-api.freemius:8080' );- }-- // Set API address for local testing.- if ( ! WP_FS__IS_PRODUCTION_MODE ) {- if ( ! defined( 'FS_API__ADDRESS' ) ) {- define( 'FS_API__ADDRESS', WP_FS__API_ADDRESS_LOCALHOST );- }- if ( ! defined( 'FS_API__SANDBOX_ADDRESS' ) ) {- define( 'FS_API__SANDBOX_ADDRESS', WP_FS__API_SANDBOX_ADDRESS_LOCALHOST );- }- }-- #endregion-- #--------------------------------------------------------------------------------- #region Checkout- #---------------------------------------------------------------------------------- if ( ! defined( 'FS_CHECKOUT__ADDRESS_PRODUCTION' ) ) {- define( 'FS_CHECKOUT__ADDRESS_PRODUCTION', 'https://checkout.freemius.com' );- }-- if ( ! defined( 'FS_CHECKOUT__ADDRESS_LOCALHOST' ) ) {- define( 'FS_CHECKOUT__ADDRESS_LOCALHOST', 'http://checkout.freemius-local.com:8080' );- }-- if ( ! defined( 'FS_CHECKOUT__ADDRESS' ) ) {- define( 'FS_CHECKOUT__ADDRESS', ( WP_FS__IS_PRODUCTION_MODE ? FS_CHECKOUT__ADDRESS_PRODUCTION : FS_CHECKOUT__ADDRESS_LOCALHOST ) );- }-- #endregion-- define( 'WP_FS___OPTION_PREFIX', 'fs' . ( WP_FS__IS_PRODUCTION_MODE ? '' : '_dbg' ) . '_' );-- if ( ! defined( 'WP_FS__ACCOUNTS_OPTION_NAME' ) ) {- define( 'WP_FS__ACCOUNTS_OPTION_NAME', WP_FS___OPTION_PREFIX . 'accounts' );- }- if ( ! defined( 'WP_FS__API_CACHE_OPTION_NAME' ) ) {- define( 'WP_FS__API_CACHE_OPTION_NAME', WP_FS___OPTION_PREFIX . 'api_cache' );- }- if ( ! defined( 'WP_FS__GDPR_OPTION_NAME' ) ) {- define( 'WP_FS__GDPR_OPTION_NAME', WP_FS___OPTION_PREFIX . 'gdpr' );- }- define( 'WP_FS__OPTIONS_OPTION_NAME', WP_FS___OPTION_PREFIX . 'options' );-- /**- * Module types- *- * @since 1.2.2- */- define( 'WP_FS__MODULE_TYPE_PLUGIN', 'plugin' );- define( 'WP_FS__MODULE_TYPE_THEME', 'theme' );-- /**- * Billing Frequencies- */- define( 'WP_FS__PERIOD_ANNUALLY', 'annual' );- define( 'WP_FS__PERIOD_MONTHLY', 'monthly' );- define( 'WP_FS__PERIOD_LIFETIME', 'lifetime' );-- /**- * Plans- */- define( 'WP_FS__PLAN_DEFAULT_PAID', false );- define( 'WP_FS__PLAN_FREE', 'free' );- define( 'WP_FS__PLAN_TRIAL', 'trial' );-- /**- * Times in seconds- */- if ( ! defined( 'WP_FS__TIME_5_MIN_IN_SEC' ) ) {- define( 'WP_FS__TIME_5_MIN_IN_SEC', 300 );- }- if ( ! defined( 'WP_FS__TIME_10_MIN_IN_SEC' ) ) {- define( 'WP_FS__TIME_10_MIN_IN_SEC', 600 );- }-// define( 'WP_FS__TIME_15_MIN_IN_SEC', 900 );- if ( ! defined( 'WP_FS__TIME_12_HOURS_IN_SEC' ) ) {- define( 'WP_FS__TIME_12_HOURS_IN_SEC', 43200 );- }- if ( ! defined( 'WP_FS__TIME_24_HOURS_IN_SEC' ) ) {- define( 'WP_FS__TIME_24_HOURS_IN_SEC', WP_FS__TIME_12_HOURS_IN_SEC * 2 );- }- if ( ! defined( 'WP_FS__TIME_WEEK_IN_SEC' ) ) {- define( 'WP_FS__TIME_WEEK_IN_SEC', 7 * WP_FS__TIME_24_HOURS_IN_SEC );- }-- #--------------------------------------------------------------------------------- #region Debugging- #---------------------------------------------------------------------------------- if ( ! defined( 'WP_FS__DEBUG_SDK' ) ) {- $debug_mode = get_option( 'fs_debug_mode', null );-- if ( $debug_mode === null ) {- $debug_mode = false;- add_option( 'fs_debug_mode', $debug_mode );- }-- define( 'WP_FS__DEBUG_SDK', is_numeric( $debug_mode ) ? ( 0 < $debug_mode ) : WP_FS__DEV_MODE );- }-- if ( ! defined( 'WP_FS__ECHO_DEBUG_SDK' ) ) {- define( 'WP_FS__ECHO_DEBUG_SDK', WP_FS__DEV_MODE && ! empty( $_GET['fs_dbg_echo'] ) );- }- if ( ! defined( 'WP_FS__LOG_DATETIME_FORMAT' ) ) {- define( 'WP_FS__LOG_DATETIME_FORMAT', 'Y-m-d H:i:s' );- }- if ( ! defined( 'FS_API__LOGGER_ON' ) ) {- define( 'FS_API__LOGGER_ON', WP_FS__DEBUG_SDK );- }-- if ( WP_FS__ECHO_DEBUG_SDK ) {- error_reporting( E_ALL );- }-- #endregion-- if ( ! defined( 'WP_FS__SCRIPT_START_TIME' ) ) {- define( 'WP_FS__SCRIPT_START_TIME', time() );- }- if ( ! defined( 'WP_FS__DEFAULT_PRIORITY' ) ) {- define( 'WP_FS__DEFAULT_PRIORITY', 10 );- }- if ( ! defined( 'WP_FS__LOWEST_PRIORITY' ) ) {- define( 'WP_FS__LOWEST_PRIORITY', 999999999 );- }-- #--------------------------------------------------------------------------------- #region Multisite Network- #---------------------------------------------------------------------------------- /**- * Do not use this define directly, it will have the wrong value- * during plugin uninstall/deletion when the inclusion of the plugin- * is triggered due to registration with register_uninstall_hook().- *- * Instead, use fs_is_network_admin().- *- * @author Vova Feldman (@svovaf)- */- if ( ! defined( 'WP_FS__IS_NETWORK_ADMIN' ) ) {- define( 'WP_FS__IS_NETWORK_ADMIN',- is_multisite() &&- ( is_network_admin() ||- ( ( defined( 'DOING_AJAX' ) && DOING_AJAX &&- ( isset( $_REQUEST['_fs_network_admin'] ) && 'true' === $_REQUEST['_fs_network_admin'] /*||- ( ! empty( $_REQUEST['action'] ) && 'delete-plugin' === $_REQUEST['action'] )*/ )- ) ||- // Plugin uninstall.- defined( 'WP_UNINSTALL_PLUGIN' ) )- )- );- }-- /**- * Do not use this define directly, it will have the wrong value- * during plugin uninstall/deletion when the inclusion of the plugin- * is triggered due to registration with register_uninstall_hook().- *- * Instead, use fs_is_blog_admin().- *- * @author Vova Feldman (@svovaf)- */- if ( ! defined( 'WP_FS__IS_BLOG_ADMIN' ) ) {- define( 'WP_FS__IS_BLOG_ADMIN', is_blog_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_REQUEST['_fs_blog_admin'] ) ) );- }-- if ( ! defined( 'WP_FS__SHOW_NETWORK_EVEN_WHEN_DELEGATED' ) ) {- // Set to true to show network level settings even if delegated to site admins.- define( 'WP_FS__SHOW_NETWORK_EVEN_WHEN_DELEGATED', false );- }-- #endregion-- if ( ! defined( 'WP_FS__DEMO_MODE' ) ) {- define( 'WP_FS__DEMO_MODE', false );- }- if ( ! defined( 'FS_SDK__SSLVERIFY' ) ) {- define( 'FS_SDK__SSLVERIFY', false );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.4 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + if ( ! defined( 'WP_FS__SLUG' ) ) { + define( 'WP_FS__SLUG', 'freemius' ); + } + if ( ! defined( 'WP_FS__DEV_MODE' ) ) { + define( 'WP_FS__DEV_MODE', false ); + } + + #-------------------------------------------------------------------------------- + #region API Connectivity Issues Simulation + #-------------------------------------------------------------------------------- + + if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY' ) ) { + define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY', false ); + } + if ( ! defined( 'WP_FS__SIMULATE_NO_CURL' ) ) { + define( 'WP_FS__SIMULATE_NO_CURL', false ); + } + if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE' ) ) { + define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', false ); + } + if ( ! defined( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL' ) ) { + define( 'WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', false ); + } + if ( WP_FS__SIMULATE_NO_CURL ) { + define( 'FS_SDK__SIMULATE_NO_CURL', true ); + } + if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE ) { + define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_CLOUDFLARE', true ); + } + if ( WP_FS__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL ) { + define( 'FS_SDK__SIMULATE_NO_API_CONNECTIVITY_SQUID_ACL', true ); + } + + #endregion + + if ( ! defined( 'WP_FS__SIMULATE_FREEMIUS_OFF' ) ) { + define( 'WP_FS__SIMULATE_FREEMIUS_OFF', false ); + } + + if ( ! defined( 'WP_FS__PING_API_ON_IP_OR_HOST_CHANGES' ) ) { + /** + * @since 1.1.7.3 + * @author Vova Feldman (@svovaf) + * + * I'm not sure if shared servers periodically change IP, or the subdomain of the + * admin dashboard. Also, I've seen sites that have strange loop of switching + * between domains on a daily basis. Therefore, to eliminate the risk of + * multiple unwanted connectivity test pings, temporary ignore domain or + * server IP changes. + */ + define( 'WP_FS__PING_API_ON_IP_OR_HOST_CHANGES', false ); + } + + /** + * If your dev environment supports custom public network IP setup + * like VVV, please update WP_FS__LOCALHOST_IP with your public IP + * and uncomment it during dev. + */ + if ( ! defined( 'WP_FS__LOCALHOST_IP' ) ) { + // VVV default public network IP. + define( 'WP_FS__VVV_DEFAULT_PUBLIC_IP', '192.168.50.4' ); + +// define( 'WP_FS__LOCALHOST_IP', WP_FS__VVV_DEFAULT_PUBLIC_IP ); + } + + /** + * If true and running with secret key, the opt-in process + * will skip the email activation process which is invoked + * when the email of the context user already exist in Freemius + * database (as a security precaution, to prevent sharing user + * secret with unauthorized entity). + * + * IMPORTANT: + * AS A SECURITY PRECAUTION, WE VALIDATE THE TIMESTAMP OF THE OPT-IN REQUEST. + * THEREFORE, MAKE SURE THAT WHEN USING THIS PARAMETER,YOUR TESTING ENVIRONMENT'S + * CLOCK IS SYNCED. + */ + if ( ! defined( 'WP_FS__SKIP_EMAIL_ACTIVATION' ) ) { + define( 'WP_FS__SKIP_EMAIL_ACTIVATION', false ); + } + + + #-------------------------------------------------------------------------------- + #region Directories + #-------------------------------------------------------------------------------- + + if ( ! defined( 'WP_FS__DIR' ) ) { + define( 'WP_FS__DIR', dirname( __FILE__ ) ); + } + if ( ! defined( 'WP_FS__DIR_INCLUDES' ) ) { + define( 'WP_FS__DIR_INCLUDES', WP_FS__DIR . '/includes' ); + } + if ( ! defined( 'WP_FS__DIR_TEMPLATES' ) ) { + define( 'WP_FS__DIR_TEMPLATES', WP_FS__DIR . '/templates' ); + } + if ( ! defined( 'WP_FS__DIR_ASSETS' ) ) { + define( 'WP_FS__DIR_ASSETS', WP_FS__DIR . '/assets' ); + } + if ( ! defined( 'WP_FS__DIR_CSS' ) ) { + define( 'WP_FS__DIR_CSS', WP_FS__DIR_ASSETS . '/css' ); + } + if ( ! defined( 'WP_FS__DIR_JS' ) ) { + define( 'WP_FS__DIR_JS', WP_FS__DIR_ASSETS . '/js' ); + } + if ( ! defined( 'WP_FS__DIR_IMG' ) ) { + define( 'WP_FS__DIR_IMG', WP_FS__DIR_ASSETS . '/img' ); + } + if ( ! defined( 'WP_FS__DIR_SDK' ) ) { + define( 'WP_FS__DIR_SDK', WP_FS__DIR_INCLUDES . '/sdk' ); + } + + #endregion + + /** + * Domain / URL / Address + */ + define( 'WP_FS__ROOT_DOMAIN_PRODUCTION', 'freemius.com' ); + define( 'WP_FS__DOMAIN_PRODUCTION', 'wp.freemius.com' ); + define( 'WP_FS__ADDRESS_PRODUCTION', 'https://' . WP_FS__DOMAIN_PRODUCTION ); + + if ( ! defined( 'WP_FS__DOMAIN_LOCALHOST' ) ) { + define( 'WP_FS__DOMAIN_LOCALHOST', 'wp.freemius' ); + } + if ( ! defined( 'WP_FS__ADDRESS_LOCALHOST' ) ) { + define( 'WP_FS__ADDRESS_LOCALHOST', 'http://' . WP_FS__DOMAIN_LOCALHOST . ':8080' ); + } + + if ( ! defined( 'WP_FS__TESTING_DOMAIN' ) ) { + define( 'WP_FS__TESTING_DOMAIN', 'fswp' ); + } + + #-------------------------------------------------------------------------------- + #region HTTP + #-------------------------------------------------------------------------------- + + if ( ! defined( 'WP_FS__IS_HTTP_REQUEST' ) ) { + define( 'WP_FS__IS_HTTP_REQUEST', isset( $_SERVER['HTTP_HOST'] ) && isset( $_SERVER['REQUEST_METHOD'] ) ); + } + + if ( ! defined( 'WP_FS__IS_HTTPS' ) ) { + define( 'WP_FS__IS_HTTPS', ( WP_FS__IS_HTTP_REQUEST && + // Checks if CloudFlare's HTTPS (Flexible SSL support). + isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && + 'https' === strtolower( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) + ) || + // Check if HTTPS request. + ( isset( $_SERVER['HTTPS'] ) && 'on' == $_SERVER['HTTPS'] ) || + ( isset( $_SERVER['SERVER_PORT'] ) && 443 == $_SERVER['SERVER_PORT'] ) + ); + } + + if ( ! defined( 'WP_FS__IS_POST_REQUEST' ) ) { + define( 'WP_FS__IS_POST_REQUEST', ( WP_FS__IS_HTTP_REQUEST && + strtoupper( $_SERVER['REQUEST_METHOD'] ) == 'POST' ) ); + } + + if ( ! defined( 'WP_FS__REMOTE_ADDR' ) ) { + define( 'WP_FS__REMOTE_ADDR', fs_get_ip() ); + } + + if ( ! defined( 'WP_FS__IS_LOCALHOST' ) ) { + if ( defined( 'WP_FS__LOCALHOST_IP' ) ) { + define( 'WP_FS__IS_LOCALHOST', ( WP_FS__LOCALHOST_IP === WP_FS__REMOTE_ADDR ) ); + } else { + define( 'WP_FS__IS_LOCALHOST', WP_FS__IS_HTTP_REQUEST && + is_string( WP_FS__REMOTE_ADDR ) && + ( substr( WP_FS__REMOTE_ADDR, 0, 4 ) === '127.' || + WP_FS__REMOTE_ADDR === '::1' ) + ); + } + } + + if ( ! defined( 'WP_FS__IS_LOCALHOST_FOR_SERVER' ) ) { + define( 'WP_FS__IS_LOCALHOST_FOR_SERVER', ( ! WP_FS__IS_HTTP_REQUEST || + false !== strpos( $_SERVER['HTTP_HOST'], 'localhost' ) ) ); + } + + #endregion + + if ( ! defined( 'WP_FS__IS_PRODUCTION_MODE' ) ) { + // By default, run with Freemius production servers. + define( 'WP_FS__IS_PRODUCTION_MODE', true ); + } + + if ( ! defined( 'WP_FS__ADDRESS' ) ) { + define( 'WP_FS__ADDRESS', ( WP_FS__IS_PRODUCTION_MODE ? WP_FS__ADDRESS_PRODUCTION : WP_FS__ADDRESS_LOCALHOST ) ); + } + + + #-------------------------------------------------------------------------------- + #region API + #-------------------------------------------------------------------------------- + + if ( ! defined( 'WP_FS__API_ADDRESS_LOCALHOST' ) ) { + define( 'WP_FS__API_ADDRESS_LOCALHOST', 'http://api.freemius-local.com:8080' ); + } + if ( ! defined( 'WP_FS__API_SANDBOX_ADDRESS_LOCALHOST' ) ) { + define( 'WP_FS__API_SANDBOX_ADDRESS_LOCALHOST', 'http://sandbox-api.freemius:8080' ); + } + + // Set API address for local testing. + if ( ! WP_FS__IS_PRODUCTION_MODE ) { + if ( ! defined( 'FS_API__ADDRESS' ) ) { + define( 'FS_API__ADDRESS', WP_FS__API_ADDRESS_LOCALHOST ); + } + if ( ! defined( 'FS_API__SANDBOX_ADDRESS' ) ) { + define( 'FS_API__SANDBOX_ADDRESS', WP_FS__API_SANDBOX_ADDRESS_LOCALHOST ); + } + } + + #endregion + + #-------------------------------------------------------------------------------- + #region Checkout + #-------------------------------------------------------------------------------- + + if ( ! defined( 'FS_CHECKOUT__ADDRESS_PRODUCTION' ) ) { + define( 'FS_CHECKOUT__ADDRESS_PRODUCTION', 'https://checkout.freemius.com' ); + } + + if ( ! defined( 'FS_CHECKOUT__ADDRESS_LOCALHOST' ) ) { + define( 'FS_CHECKOUT__ADDRESS_LOCALHOST', 'http://checkout.freemius-local.com:8080' ); + } + + if ( ! defined( 'FS_CHECKOUT__ADDRESS' ) ) { + define( 'FS_CHECKOUT__ADDRESS', ( WP_FS__IS_PRODUCTION_MODE ? FS_CHECKOUT__ADDRESS_PRODUCTION : FS_CHECKOUT__ADDRESS_LOCALHOST ) ); + } + + #endregion + + define( 'WP_FS___OPTION_PREFIX', 'fs' . ( WP_FS__IS_PRODUCTION_MODE ? '' : '_dbg' ) . '_' ); + + if ( ! defined( 'WP_FS__ACCOUNTS_OPTION_NAME' ) ) { + define( 'WP_FS__ACCOUNTS_OPTION_NAME', WP_FS___OPTION_PREFIX . 'accounts' ); + } + if ( ! defined( 'WP_FS__API_CACHE_OPTION_NAME' ) ) { + define( 'WP_FS__API_CACHE_OPTION_NAME', WP_FS___OPTION_PREFIX . 'api_cache' ); + } + if ( ! defined( 'WP_FS__GDPR_OPTION_NAME' ) ) { + define( 'WP_FS__GDPR_OPTION_NAME', WP_FS___OPTION_PREFIX . 'gdpr' ); + } + define( 'WP_FS__OPTIONS_OPTION_NAME', WP_FS___OPTION_PREFIX . 'options' ); + + /** + * Module types + * + * @since 1.2.2 + */ + define( 'WP_FS__MODULE_TYPE_PLUGIN', 'plugin' ); + define( 'WP_FS__MODULE_TYPE_THEME', 'theme' ); + + /** + * Billing Frequencies + */ + define( 'WP_FS__PERIOD_ANNUALLY', 'annual' ); + define( 'WP_FS__PERIOD_MONTHLY', 'monthly' ); + define( 'WP_FS__PERIOD_LIFETIME', 'lifetime' ); + + /** + * Plans + */ + define( 'WP_FS__PLAN_DEFAULT_PAID', false ); + define( 'WP_FS__PLAN_FREE', 'free' ); + define( 'WP_FS__PLAN_TRIAL', 'trial' ); + + /** + * Times in seconds + */ + if ( ! defined( 'WP_FS__TIME_5_MIN_IN_SEC' ) ) { + define( 'WP_FS__TIME_5_MIN_IN_SEC', 300 ); + } + if ( ! defined( 'WP_FS__TIME_10_MIN_IN_SEC' ) ) { + define( 'WP_FS__TIME_10_MIN_IN_SEC', 600 ); + } +// define( 'WP_FS__TIME_15_MIN_IN_SEC', 900 ); + if ( ! defined( 'WP_FS__TIME_12_HOURS_IN_SEC' ) ) { + define( 'WP_FS__TIME_12_HOURS_IN_SEC', 43200 ); + } + if ( ! defined( 'WP_FS__TIME_24_HOURS_IN_SEC' ) ) { + define( 'WP_FS__TIME_24_HOURS_IN_SEC', WP_FS__TIME_12_HOURS_IN_SEC * 2 ); + } + if ( ! defined( 'WP_FS__TIME_WEEK_IN_SEC' ) ) { + define( 'WP_FS__TIME_WEEK_IN_SEC', 7 * WP_FS__TIME_24_HOURS_IN_SEC ); + } + + #-------------------------------------------------------------------------------- + #region Debugging + #-------------------------------------------------------------------------------- + + if ( ! defined( 'WP_FS__DEBUG_SDK' ) ) { + $debug_mode = get_option( 'fs_debug_mode', null ); + + if ( $debug_mode === null ) { + $debug_mode = false; + add_option( 'fs_debug_mode', $debug_mode ); + } + + define( 'WP_FS__DEBUG_SDK', is_numeric( $debug_mode ) ? ( 0 < $debug_mode ) : WP_FS__DEV_MODE ); + } + + if ( ! defined( 'WP_FS__ECHO_DEBUG_SDK' ) ) { + define( 'WP_FS__ECHO_DEBUG_SDK', WP_FS__DEV_MODE && ! empty( $_GET['fs_dbg_echo'] ) ); + } + if ( ! defined( 'WP_FS__LOG_DATETIME_FORMAT' ) ) { + define( 'WP_FS__LOG_DATETIME_FORMAT', 'Y-m-d H:i:s' ); + } + if ( ! defined( 'FS_API__LOGGER_ON' ) ) { + define( 'FS_API__LOGGER_ON', WP_FS__DEBUG_SDK ); + } + + if ( WP_FS__ECHO_DEBUG_SDK ) { + error_reporting( E_ALL ); + } + + #endregion + + if ( ! defined( 'WP_FS__SCRIPT_START_TIME' ) ) { + define( 'WP_FS__SCRIPT_START_TIME', time() ); + } + if ( ! defined( 'WP_FS__DEFAULT_PRIORITY' ) ) { + define( 'WP_FS__DEFAULT_PRIORITY', 10 ); + } + if ( ! defined( 'WP_FS__LOWEST_PRIORITY' ) ) { + define( 'WP_FS__LOWEST_PRIORITY', 999999999 ); + } + + #-------------------------------------------------------------------------------- + #region Multisite Network + #-------------------------------------------------------------------------------- + + /** + * Do not use this define directly, it will have the wrong value + * during plugin uninstall/deletion when the inclusion of the plugin + * is triggered due to registration with register_uninstall_hook(). + * + * Instead, use fs_is_network_admin(). + * + * @author Vova Feldman (@svovaf) + */ + if ( ! defined( 'WP_FS__IS_NETWORK_ADMIN' ) ) { + define( 'WP_FS__IS_NETWORK_ADMIN', + is_multisite() && + ( is_network_admin() || + ( ( defined( 'DOING_AJAX' ) && DOING_AJAX && + ( isset( $_REQUEST['_fs_network_admin'] ) && 'true' === $_REQUEST['_fs_network_admin'] /*|| + ( ! empty( $_REQUEST['action'] ) && 'delete-plugin' === $_REQUEST['action'] )*/ ) + ) || + // Plugin uninstall. + defined( 'WP_UNINSTALL_PLUGIN' ) ) + ) + ); + } + + /** + * Do not use this define directly, it will have the wrong value + * during plugin uninstall/deletion when the inclusion of the plugin + * is triggered due to registration with register_uninstall_hook(). + * + * Instead, use fs_is_blog_admin(). + * + * @author Vova Feldman (@svovaf) + */ + if ( ! defined( 'WP_FS__IS_BLOG_ADMIN' ) ) { + define( 'WP_FS__IS_BLOG_ADMIN', is_blog_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_REQUEST['_fs_blog_admin'] ) ) ); + } + + if ( ! defined( 'WP_FS__SHOW_NETWORK_EVEN_WHEN_DELEGATED' ) ) { + // Set to true to show network level settings even if delegated to site admins. + define( 'WP_FS__SHOW_NETWORK_EVEN_WHEN_DELEGATED', false ); + } + + #endregion + + if ( ! defined( 'WP_FS__DEMO_MODE' ) ) { + define( 'WP_FS__DEMO_MODE', false ); + } + if ( ! defined( 'FS_SDK__SSLVERIFY' ) ) { + define( 'FS_SDK__SSLVERIFY', false ); + }
Vulnerability Existed: no No Vulnerabilities Found - inc/freemius/config.php This diff shows only line ending changes (Unix LF vs Windows CRLF format conversion). The actual code content remains identical between versions 1.2.11 and 1.2.12. No security fixes or vulnerabilities are present in this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/class-freemius-abstract.php 2026-01-19 00:16:00.441014443 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/class-freemius-abstract.php 2026-01-19 00:17:37.651045032 +0000@@ -1,538 +1,538 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.7- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }--- /**- * - Each instance of Freemius class represents a single plugin- * install by a single user (the installer of the plugin).- *- * - Each website can only have one install of the same plugin.- *- * - Install entity is only created after a user connects his account with Freemius.- *- * Class Freemius_Abstract- */- abstract class Freemius_Abstract {-- #----------------------------------------------------------------------------------- #region Identity- #------------------------------------------------------------------------------------ /**- * Check if user has connected his account (opted-in).- *- * Note:- * If the user opted-in and opted-out on a later stage,- * this will still return true. If you want to check if the- * user is currently opted-in, use:- * `$fs->is_registered() && $fs->is_tracking_allowed()`- *- * @since 1.0.1- *- * @param bool $ignore_anonymous_state Since 2.5.1- *- * @return bool- */- abstract function is_registered( $ignore_anonymous_state = false );-- /**- * Check if the user skipped connecting the account with Freemius.- *- * @since 1.0.7- *- * @return bool- */- abstract function is_anonymous();-- /**- * Check if the user currently in activation mode.- *- * @since 1.0.7- *- * @return bool- */- abstract function is_activation_mode();-- #endregion-- #----------------------------------------------------------------------------------- #region Module Type- #------------------------------------------------------------------------------------ /**- * Checks if the plugin's type is "plugin". The other type is "theme".- *- * @author Leo Fajardo (@leorw)- * @since 1.2.2- *- * @return bool- */- abstract function is_plugin();-- /**- * Checks if the module type is "theme". The other type is "plugin".- *- * @author Leo Fajardo (@leorw)- * @since 1.2.2- *- * @return bool- */- function is_theme() {- return ( ! $this->is_plugin() );- }-- #endregion-- #----------------------------------------------------------------------------------- #region Permissions- #------------------------------------------------------------------------------------ /**- * Check if plugin must be WordPress.org compliant.- *- * @since 1.0.7- *- * @return bool- */- abstract function is_org_repo_compliant();-- /**- * Check if plugin is allowed to install executable files.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.5- *- * @return bool- */- function is_allowed_to_install() {- return ( $this->is_premium() || ! $this->is_org_repo_compliant() );- }-- #endregion-- /**- * Check if user in trial or in free plan (not paying).- *- * @author Vova Feldman (@svovaf)- * @since 1.0.4- *- * @return bool- */- function is_not_paying() {- return ( $this->is_trial() || $this->is_free_plan() );- }-- /**- * Check if the user has an activated and valid paid license on current plugin's install.- *- * @since 1.0.9- *- * @return bool- */- abstract function is_paying();-- /**- * Check if the user is paying or in trial.- *- * @since 1.0.9- *- * @return bool- */- function is_paying_or_trial() {- return ( $this->is_paying() || $this->is_trial() );- }-- /**- * Check if user in a trial or have feature enabled license.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.7- *- * @return bool- */- abstract function can_use_premium_code();-- #----------------------------------------------------------------------------------- #region Premium Only- #------------------------------------------------------------------------------------ /**- * All logic wrapped in methods with "__premium_only()" suffix will be only- * included in the premium code.- *- * Example:- * if ( freemius()->is__premium_only() ) {- * ...- * }- */-- /**- * Returns true when running premium plugin code.- *- * @since 1.0.9- *- * @return bool- */- function is__premium_only() {- return $this->is_premium();- }-- /**- * Check if the user has an activated and valid paid license on current plugin's install.- *- * @since 1.0.9- *- * @return bool- *- */- function is_paying__premium_only() {- return ( $this->is__premium_only() && $this->is_paying() );- }-- /**- * All code wrapped in this statement will be only included in the premium code.- *- * @since 1.0.9- *- * @param string $plan Plan name.- * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.- *- * @return bool- */- function is_plan__premium_only( $plan, $exact = false ) {- return ( $this->is_premium() && $this->is_plan( $plan, $exact ) );- }-- /**- * Check if plan matches active license' plan or active trial license' plan.- *- * All code wrapped in this statement will be only included in the premium code.- *- * @since 1.0.9- *- * @param string $plan Plan name.- * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.- *- * @return bool- */- function is_plan_or_trial__premium_only( $plan, $exact = false ) {- return ( $this->is_premium() && $this->is_plan_or_trial( $plan, $exact ) );- }-- /**- * Check if the user is paying or in trial.- *- * All code wrapped in this statement will be only included in the premium code.- *- * @since 1.0.9- *- * @return bool- */- function is_paying_or_trial__premium_only() {- return $this->is_premium() && $this->is_paying_or_trial();- }-- /**- * Check if the user has an activated and valid paid license on current plugin's install.- *- * @since 1.0.4- *- * @return bool- *- * @deprecated Method name is confusing since it's not clear from the name the code will be removed.- * @using Alias to is_paying__premium_only()- */- function is_paying__fs__() {- return $this->is_paying__premium_only();- }-- /**- * Check if user in a trial or have feature enabled license.- *- * All code wrapped in this statement will be only included in the premium code.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.9- *- * @return bool- */- function can_use_premium_code__premium_only() {- return $this->is_premium() && $this->can_use_premium_code();- }-- #endregion-- #----------------------------------------------------------------------------------- #region Trial- #------------------------------------------------------------------------------------ /**- * Check if the user in a trial.- *- * @since 1.0.3- *- * @return bool- */- abstract function is_trial();-- /**- * Check if trial already utilized.- *- * @since 1.0.9- *- * @return bool- */- abstract function is_trial_utilized();-- #endregion-- #----------------------------------------------------------------------------------- #region Plans- #------------------------------------------------------------------------------------ /**- * Check if the user is on the free plan of the product.- *- * @since 1.0.4- *- * @return bool- */- abstract function is_free_plan();-- /**- * @since 1.0.2- *- * @param string $plan Plan name.- * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.- *- * @return bool- */- abstract function is_plan( $plan, $exact = false );-- /**- * Check if plan based on trial. If not in trial mode, should return false.- *- * @since 1.0.9- *- * @param string $plan Plan name.- * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.- *- * @return bool- */- abstract function is_trial_plan( $plan, $exact = false );-- /**- * Check if plan matches active license' plan or active trial license' plan.- *- * @since 1.0.9- *- * @param string $plan Plan name.- * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans.- *- * @return bool- */- function is_plan_or_trial( $plan, $exact = false ) {- return $this->is_plan( $plan, $exact ) ||- $this->is_trial_plan( $plan, $exact );- }-- /**- * Check if plugin has any paid plans.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @return bool- */- abstract function has_paid_plan();-- /**- * Check if plugin has any free plan, or is it premium only.- *- * Note: If no plans configured, assume plugin is free.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @return bool- */- abstract function has_free_plan();-- /**- * Check if plugin is premium only (no free plans).- *- * NOTE: is__premium_only() is very different method, don't get confused.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.9- *- * @return bool- */- abstract function is_only_premium();-- /**- * Check if module has a premium code version.- *- * Serviceware module might be freemium without any- * premium code version, where the paid features- * are all part of the service.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @return bool- */- abstract function has_premium_version();-- /**- * Check if module has any release on Freemius,- * or all plugin's code is on WordPress.org (Serviceware).- *- * @return bool- */- function has_release_on_freemius() {- return ! $this->is_org_repo_compliant() ||- $this->has_premium_version();- }-- /**- * Checks if it's a freemium plugin.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.9- *- * @return bool- */- function is_freemium() {- return $this->has_paid_plan() &&- $this->has_free_plan();- }-- /**- * Check if module has only one plan.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.7- *- * @return bool- */- abstract function is_single_plan();-- #endregion-- /**- * Check if running payments in sandbox mode.- *- * @since 1.0.4- *- * @return bool- */- abstract function is_payments_sandbox();-- /**- * Check if running test vs. live plugin.- *- * @since 1.0.5- *- * @return bool- */- abstract function is_live();-- /**- * Check if running premium plugin code.- *- * @since 1.0.5- *- * @return bool- */- abstract function is_premium();-- /**- * Get upgrade URL.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.2- *- * @param string $period Billing cycle.- *- * @return string- */- abstract function get_upgrade_url( $period = WP_FS__PERIOD_ANNUALLY );-- /**- * Check if Freemius was first added in a plugin update.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.5- *- * @return bool- */- function is_plugin_update() {- return ! $this->is_plugin_new_install();- }-- /**- * Check if Freemius was part of the plugin when the user installed it first.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.5- *- * @return bool- */- abstract function is_plugin_new_install();-- #----------------------------------------------------------------------------------- #region Marketing- #------------------------------------------------------------------------------------ /**- * Check if current user purchased any other plugins before.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- abstract function has_purchased_before();-- /**- * Check if current user classified as an agency.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- abstract function is_agency();-- /**- * Check if current user classified as a developer.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- abstract function is_developer();-- /**- * Check if current user classified as a business.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- abstract function is_business();-- #endregion+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.7 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + + /** + * - Each instance of Freemius class represents a single plugin + * install by a single user (the installer of the plugin). + * + * - Each website can only have one install of the same plugin. + * + * - Install entity is only created after a user connects his account with Freemius. + * + * Class Freemius_Abstract + */ + abstract class Freemius_Abstract { + + #---------------------------------------------------------------------------------- + #region Identity + #---------------------------------------------------------------------------------- + + /** + * Check if user has connected his account (opted-in). + * + * Note: + * If the user opted-in and opted-out on a later stage, + * this will still return true. If you want to check if the + * user is currently opted-in, use: + * `$fs->is_registered() && $fs->is_tracking_allowed()` + * + * @since 1.0.1 + * + * @param bool $ignore_anonymous_state Since 2.5.1 + * + * @return bool + */ + abstract function is_registered( $ignore_anonymous_state = false ); + + /** + * Check if the user skipped connecting the account with Freemius. + * + * @since 1.0.7 + * + * @return bool + */ + abstract function is_anonymous(); + + /** + * Check if the user currently in activation mode. + * + * @since 1.0.7 + * + * @return bool + */ + abstract function is_activation_mode(); + + #endregion + + #---------------------------------------------------------------------------------- + #region Module Type + #---------------------------------------------------------------------------------- + + /** + * Checks if the plugin's type is "plugin". The other type is "theme". + * + * @author Leo Fajardo (@leorw) + * @since 1.2.2 + * + * @return bool + */ + abstract function is_plugin(); + + /** + * Checks if the module type is "theme". The other type is "plugin". + * + * @author Leo Fajardo (@leorw) + * @since 1.2.2 + * + * @return bool + */ + function is_theme() { + return ( ! $this->is_plugin() ); + } + + #endregion + + #---------------------------------------------------------------------------------- + #region Permissions + #---------------------------------------------------------------------------------- + + /** + * Check if plugin must be WordPress.org compliant. + * + * @since 1.0.7 + * + * @return bool + */ + abstract function is_org_repo_compliant(); + + /** + * Check if plugin is allowed to install executable files. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.5 + * + * @return bool + */ + function is_allowed_to_install() { + return ( $this->is_premium() || ! $this->is_org_repo_compliant() ); + } + + #endregion + + /** + * Check if user in trial or in free plan (not paying). + * + * @author Vova Feldman (@svovaf) + * @since 1.0.4 + * + * @return bool + */ + function is_not_paying() { + return ( $this->is_trial() || $this->is_free_plan() ); + } + + /** + * Check if the user has an activated and valid paid license on current plugin's install. + * + * @since 1.0.9 + * + * @return bool + */ + abstract function is_paying(); + + /** + * Check if the user is paying or in trial. + * + * @since 1.0.9 + * + * @return bool + */ + function is_paying_or_trial() { + return ( $this->is_paying() || $this->is_trial() ); + } + + /** + * Check if user in a trial or have feature enabled license. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.7 + * + * @return bool + */ + abstract function can_use_premium_code(); + + #---------------------------------------------------------------------------------- + #region Premium Only + #---------------------------------------------------------------------------------- + + /** + * All logic wrapped in methods with "__premium_only()" suffix will be only + * included in the premium code. + * + * Example: + * if ( freemius()->is__premium_only() ) { + * ... + * } + */ + + /** + * Returns true when running premium plugin code. + * + * @since 1.0.9 + * + * @return bool + */ + function is__premium_only() { + return $this->is_premium(); + } + + /** + * Check if the user has an activated and valid paid license on current plugin's install. + * + * @since 1.0.9 + * + * @return bool + * + */ + function is_paying__premium_only() { + return ( $this->is__premium_only() && $this->is_paying() ); + } + + /** + * All code wrapped in this statement will be only included in the premium code. + * + * @since 1.0.9 + * + * @param string $plan Plan name. + * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans. + * + * @return bool + */ + function is_plan__premium_only( $plan, $exact = false ) { + return ( $this->is_premium() && $this->is_plan( $plan, $exact ) ); + } + + /** + * Check if plan matches active license' plan or active trial license' plan. + * + * All code wrapped in this statement will be only included in the premium code. + * + * @since 1.0.9 + * + * @param string $plan Plan name. + * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans. + * + * @return bool + */ + function is_plan_or_trial__premium_only( $plan, $exact = false ) { + return ( $this->is_premium() && $this->is_plan_or_trial( $plan, $exact ) ); + } + + /** + * Check if the user is paying or in trial. + * + * All code wrapped in this statement will be only included in the premium code. + * + * @since 1.0.9 + * + * @return bool + */ + function is_paying_or_trial__premium_only() { + return $this->is_premium() && $this->is_paying_or_trial(); + } + + /** + * Check if the user has an activated and valid paid license on current plugin's install. + * + * @since 1.0.4 + * + * @return bool + * + * @deprecated Method name is confusing since it's not clear from the name the code will be removed. + * @using Alias to is_paying__premium_only() + */ + function is_paying__fs__() { + return $this->is_paying__premium_only(); + } + + /** + * Check if user in a trial or have feature enabled license. + * + * All code wrapped in this statement will be only included in the premium code. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.9 + * + * @return bool + */ + function can_use_premium_code__premium_only() { + return $this->is_premium() && $this->can_use_premium_code(); + } + + #endregion + + #---------------------------------------------------------------------------------- + #region Trial + #---------------------------------------------------------------------------------- + + /** + * Check if the user in a trial. + * + * @since 1.0.3 + * + * @return bool + */ + abstract function is_trial(); + + /** + * Check if trial already utilized. + * + * @since 1.0.9 + * + * @return bool + */ + abstract function is_trial_utilized(); + + #endregion + + #---------------------------------------------------------------------------------- + #region Plans + #---------------------------------------------------------------------------------- + + /** + * Check if the user is on the free plan of the product. + * + * @since 1.0.4 + * + * @return bool + */ + abstract function is_free_plan(); + + /** + * @since 1.0.2 + * + * @param string $plan Plan name. + * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans. + * + * @return bool + */ + abstract function is_plan( $plan, $exact = false ); + + /** + * Check if plan based on trial. If not in trial mode, should return false. + * + * @since 1.0.9 + * + * @param string $plan Plan name. + * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans. + * + * @return bool + */ + abstract function is_trial_plan( $plan, $exact = false ); + + /** + * Check if plan matches active license' plan or active trial license' plan. + * + * @since 1.0.9 + * + * @param string $plan Plan name. + * @param bool $exact If true, looks for exact plan. If false, also check "higher" plans. + * + * @return bool + */ + function is_plan_or_trial( $plan, $exact = false ) { + return $this->is_plan( $plan, $exact ) || + $this->is_trial_plan( $plan, $exact ); + } + + /** + * Check if plugin has any paid plans. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @return bool + */ + abstract function has_paid_plan(); + + /** + * Check if plugin has any free plan, or is it premium only. + * + * Note: If no plans configured, assume plugin is free. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @return bool + */ + abstract function has_free_plan(); + + /** + * Check if plugin is premium only (no free plans). + * + * NOTE: is__premium_only() is very different method, don't get confused. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.9 + * + * @return bool + */ + abstract function is_only_premium(); + + /** + * Check if module has a premium code version. + * + * Serviceware module might be freemium without any + * premium code version, where the paid features + * are all part of the service. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.1.6 + * + * @return bool + */ + abstract function has_premium_version(); + + /** + * Check if module has any release on Freemius, + * or all plugin's code is on WordPress.org (Serviceware). + * + * @return bool + */ + function has_release_on_freemius() { + return ! $this->is_org_repo_compliant() || + $this->has_premium_version(); + } + + /** + * Checks if it's a freemium plugin. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.9 + * + * @return bool + */ + function is_freemium() { + return $this->has_paid_plan() && + $this->has_free_plan(); + } + + /** + * Check if module has only one plan. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.1.7 + * + * @return bool + */ + abstract function is_single_plan(); + + #endregion + + /** + * Check if running payments in sandbox mode. + * + * @since 1.0.4 + * + * @return bool + */ + abstract function is_payments_sandbox(); + + /** + * Check if running test vs. live plugin. + * + * @since 1.0.5 + * + * @return bool + */ + abstract function is_live(); + + /** + * Check if running premium plugin code. + * + * @since 1.0.5 + * + * @return bool + */ + abstract function is_premium(); + + /** + * Get upgrade URL.
Vulnerability Existed: no Analysis Summary: This diff shows only **whitespace changes** (line ending normalization from Unix LF to likely DOS CRLF or similar line ending format conversion). The actual code content remains identical between versions 1.2.11 and 1.2.12. **No Security Vulnerabilities Detected** The file `inc/freemius/includes/class-freemius-abstract.php` contains only abstract method declarations and documentation. The changes are purely formatting-related: - Line endings have been modified - No code logic has changed - No new code has been introduced - No existing code has been removed or altered Since the functional code is unchanged, there are no security fixes, regressions, or new vulnerabilities introduced in this update. This appears to be a maintenance release focusing on code standardization without any substantive modifications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/class-fs-admin-notices.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/class-fs-admin-notices.php 2026-01-19 00:17:37.655045280 +0000@@ -1,353 +1,353 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.0.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * WP Admin notices manager both for site level and network level.- *- * Class FS_Admin_Notices- */- class FS_Admin_Notices {- /**- * @since 1.2.2- *- * @var string- */- protected $_module_unique_affix;- /**- * @var string- */- protected $_id;- /**- * @var string- */- protected $_title;- /**- * @var FS_Admin_Notice_Manager- */- protected $_notices;- /**- * @var FS_Admin_Notice_Manager- */- protected $_network_notices;- /**- * @var int The ID of the blog that is associated with the current site level options.- */- private $_blog_id = 0;- /**- * @var bool- */- private $_is_multisite;- /**- * @var FS_Admin_Notices[]- */- private static $_instances = array();-- /**- * @param string $id- * @param string $title- * @param string $module_unique_affix- * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and- * blog admin pages.- *- * @return FS_Admin_Notices- */- static function instance( $id, $title = '', $module_unique_affix = '', $is_network_and_blog_admins = false ) {- if ( ! isset( self::$_instances[ $id ] ) ) {- self::$_instances[ $id ] = new FS_Admin_Notices( $id, $title, $module_unique_affix, $is_network_and_blog_admins );- }-- return self::$_instances[ $id ];- }-- /**- * @param string $id- * @param string $title- * @param string $module_unique_affix- * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and- * blog admin pages.- */- protected function __construct( $id, $title = '', $module_unique_affix = '', $is_network_and_blog_admins = false ) {- $this->_id = $id;- $this->_title = $title;- $this->_module_unique_affix = $module_unique_affix;- $this->_is_multisite = is_multisite();-- if ( $this->_is_multisite ) {- $this->_blog_id = get_current_blog_id();-- $this->_network_notices = FS_Admin_Notice_Manager::instance(- $id,- $title,- $module_unique_affix,- $is_network_and_blog_admins,- true- );- }-- $this->_notices = FS_Admin_Notice_Manager::instance(- $id,- $title,- $module_unique_affix,- false,- $this->_blog_id- );- }-- /**- * Add admin message to admin messages queue, and hook to admin_notices / all_admin_notices if not yet hooked.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.4- *- * @param string $message- * @param string $title- * @param string $type- * @param bool $is_sticky- * @param string $id Message ID- * @param bool $store_if_sticky- * @param int|null $network_level_or_blog_id- *- * @uses add_action()- */- function add(- $message,- $title = '',- $type = 'success',- $is_sticky = false,- $id = '',- $store_if_sticky = true,- $network_level_or_blog_id = null,- $is_dimissible = null- ) {- $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id );-- $notices->add(- $message,- $title,- $type,- $is_sticky,- $id,- $store_if_sticky,- null,- null,- false,- $is_dimissible- );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @param string|string[] $ids- * @param int|null $network_level_or_blog_id- * @param bool $store- */- function remove_sticky( $ids, $network_level_or_blog_id = null, $store = true ) {- if ( ! is_array( $ids ) ) {- $ids = array( $ids );- }-- if ( $this->should_use_network_notices( $ids[0], $network_level_or_blog_id ) ) {- $notices = $this->_network_notices;- } else {- $notices = $this->get_site_notices( $network_level_or_blog_id );- }-- return $notices->remove_sticky( $ids, $store );- }-- /**- * Check if sticky message exists by id.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @param string $id- * @param int|null $network_level_or_blog_id- *- * @return bool- */- function has_sticky( $id, $network_level_or_blog_id = null ) {- $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id );-- return $notices->has_sticky( $id );- }-- /**- * Adds sticky admin notification.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @param string $message- * @param string $id Message ID- * @param string $title- * @param string $type- * @param int|null $network_level_or_blog_id- * @param number|null $wp_user_id- * @param string|null $plugin_title- * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and- * blog admin pages.- * @param bool $is_dismissible- */- function add_sticky(- $message,- $id,- $title = '',- $type = 'success',- $network_level_or_blog_id = null,- $wp_user_id = null,- $plugin_title = null,- $is_network_and_blog_admins = false,- $is_dismissible = true,- $data = array()- ) {- $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id );-- $notices->add_sticky( $message, $id, $title, $type, $wp_user_id, $plugin_title, $is_network_and_blog_admins, $is_dismissible, $data );- }-- /**- * Retrieves the data of a sticky notice.- *- * @author Leo Fajardo (@leorw)- * @since 2.4.3- *- * @param string $id- * @param int|null $network_level_or_blog_id- *- * @return array|null- */- function get_sticky( $id, $network_level_or_blog_id ) {- $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id );-- return $notices->get_sticky( $id );- }-- /**- * Clear all sticky messages.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param int|null $network_level_or_blog_id- * @param bool $is_temporary- */- function clear_all_sticky( $network_level_or_blog_id = null, $is_temporary = false ) {- if ( ! $this->_is_multisite ||- false === $network_level_or_blog_id ||- 0 == $network_level_or_blog_id ||- is_null( $network_level_or_blog_id )- ) {- $notices = $this->get_site_notices( $network_level_or_blog_id );- $notices->clear_all_sticky( $is_temporary );- }-- if ( $this->_is_multisite &&- ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )- ) {- $this->_network_notices->clear_all_sticky( $is_temporary );- }- }-- /**- * Add admin message to all admin messages queue, and hook to all_admin_notices if not yet hooked.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.4- *- * @param string $message- * @param string $title- * @param string $type- * @param bool $is_sticky- * @param string $id Message ID- */- function add_all( $message, $title = '', $type = 'success', $is_sticky = false, $id = '' ) {- $this->add( $message, $title, $type, $is_sticky, true, $id );- }-- #--------------------------------------------------------------------------------- #region Helper Methods- #---------------------------------------------------------------------------------- /**- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param int $blog_id- *- * @return FS_Admin_Notice_Manager- */- private function get_site_notices( $blog_id = 0 ) {- if ( 0 == $blog_id || $blog_id == $this->_blog_id ) {- return $this->_notices;- }-- return FS_Admin_Notice_Manager::instance(- $this->_id,- $this->_title,- $this->_module_unique_affix,- false,- $blog_id- );- }-- /**- * Check if the network notices should be used.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param string $id- * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite notices (if there's a network). When `false`, use the current context blog notices. When `null`, the decision which notices manager to use (MS vs. Current S) will be handled internally and determined based on the $id and the context admin (blog admin vs. network level admin).- *- * @return bool- */- private function should_use_network_notices( $id = '', $network_level_or_blog_id = null ) {- if ( ! $this->_is_multisite ) {- // Not a multisite environment.- return false;- }-- if ( is_numeric( $network_level_or_blog_id ) ) {- // Explicitly asked to use a specified blog storage.- return false;- }-- if ( is_bool( $network_level_or_blog_id ) ) {- // Explicitly specified whether should use the network or blog level storage.- return $network_level_or_blog_id;- }-- return fs_is_network_admin();- }-- /**- * Retrieves an instance of FS_Admin_Notice_Manager.- *- * @author Leo Fajardo (@leorw)- * @since 2.5.0- *- * @param string $id- * @param int|null $network_level_or_blog_id- *- * @return FS_Admin_Notice_Manager- */- private function get_site_or_network_notices( $id, $network_level_or_blog_id ) {- return $this->should_use_network_notices( $id, $network_level_or_blog_id ) ?- $this->_network_notices :- $this->get_site_notices( $network_level_or_blog_id );- }-- #endregion+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.0.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * WP Admin notices manager both for site level and network level. + * + * Class FS_Admin_Notices + */ + class FS_Admin_Notices { + /** + * @since 1.2.2 + * + * @var string + */ + protected $_module_unique_affix; + /** + * @var string + */ + protected $_id; + /** + * @var string + */ + protected $_title; + /** + * @var FS_Admin_Notice_Manager + */ + protected $_notices; + /** + * @var FS_Admin_Notice_Manager + */ + protected $_network_notices; + /** + * @var int The ID of the blog that is associated with the current site level options. + */ + private $_blog_id = 0; + /** + * @var bool + */ + private $_is_multisite; + /** + * @var FS_Admin_Notices[] + */ + private static $_instances = array(); + + /** + * @param string $id + * @param string $title + * @param string $module_unique_affix + * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and + * blog admin pages. + * + * @return FS_Admin_Notices + */ + static function instance( $id, $title = '', $module_unique_affix = '', $is_network_and_blog_admins = false ) { + if ( ! isset( self::$_instances[ $id ] ) ) { + self::$_instances[ $id ] = new FS_Admin_Notices( $id, $title, $module_unique_affix, $is_network_and_blog_admins ); + } + + return self::$_instances[ $id ]; + } + + /** + * @param string $id + * @param string $title + * @param string $module_unique_affix + * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and + * blog admin pages. + */ + protected function __construct( $id, $title = '', $module_unique_affix = '', $is_network_and_blog_admins = false ) { + $this->_id = $id; + $this->_title = $title; + $this->_module_unique_affix = $module_unique_affix; + $this->_is_multisite = is_multisite(); + + if ( $this->_is_multisite ) { + $this->_blog_id = get_current_blog_id(); + + $this->_network_notices = FS_Admin_Notice_Manager::instance( + $id, + $title, + $module_unique_affix, + $is_network_and_blog_admins, + true + ); + } + + $this->_notices = FS_Admin_Notice_Manager::instance( + $id, + $title, + $module_unique_affix, + false, + $this->_blog_id + ); + } + + /** + * Add admin message to admin messages queue, and hook to admin_notices / all_admin_notices if not yet hooked. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.4 + * + * @param string $message + * @param string $title + * @param string $type + * @param bool $is_sticky + * @param string $id Message ID + * @param bool $store_if_sticky + * @param int|null $network_level_or_blog_id + * + * @uses add_action() + */ + function add( + $message, + $title = '', + $type = 'success', + $is_sticky = false, + $id = '', + $store_if_sticky = true, + $network_level_or_blog_id = null, + $is_dimissible = null + ) { + $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id ); + + $notices->add( + $message, + $title, + $type, + $is_sticky, + $id, + $store_if_sticky, + null, + null, + false, + $is_dimissible + ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @param string|string[] $ids + * @param int|null $network_level_or_blog_id + * @param bool $store + */ + function remove_sticky( $ids, $network_level_or_blog_id = null, $store = true ) { + if ( ! is_array( $ids ) ) { + $ids = array( $ids ); + } + + if ( $this->should_use_network_notices( $ids[0], $network_level_or_blog_id ) ) { + $notices = $this->_network_notices; + } else { + $notices = $this->get_site_notices( $network_level_or_blog_id ); + } + + return $notices->remove_sticky( $ids, $store ); + } + + /** + * Check if sticky message exists by id. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @param string $id + * @param int|null $network_level_or_blog_id + * + * @return bool + */ + function has_sticky( $id, $network_level_or_blog_id = null ) { + $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id ); + + return $notices->has_sticky( $id ); + } + + /** + * Adds sticky admin notification. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @param string $message + * @param string $id Message ID + * @param string $title + * @param string $type + * @param int|null $network_level_or_blog_id + * @param number|null $wp_user_id + * @param string|null $plugin_title + * @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and + * blog admin pages. + * @param bool $is_dismissible + */ + function add_sticky( + $message, + $id, + $title = '', + $type = 'success', + $network_level_or_blog_id = null, + $wp_user_id = null, + $plugin_title = null, + $is_network_and_blog_admins = false, + $is_dismissible = true, + $data = array() + ) { + $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id ); + + $notices->add_sticky( $message, $id, $title, $type, $wp_user_id, $plugin_title, $is_network_and_blog_admins, $is_dismissible, $data ); + } + + /** + * Retrieves the data of a sticky notice. + * + * @author Leo Fajardo (@leorw) + * @since 2.4.3 + * + * @param string $id + * @param int|null $network_level_or_blog_id + * + * @return array|null + */ + function get_sticky( $id, $network_level_or_blog_id ) { + $notices = $this->get_site_or_network_notices( $id, $network_level_or_blog_id ); + + return $notices->get_sticky( $id ); + } + + /** + * Clear all sticky messages. + * + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + * + * @param int|null $network_level_or_blog_id + * @param bool $is_temporary + */ + function clear_all_sticky( $network_level_or_blog_id = null, $is_temporary = false ) { + if ( ! $this->_is_multisite || + false === $network_level_or_blog_id || + 0 == $network_level_or_blog_id || + is_null( $network_level_or_blog_id ) + ) { + $notices = $this->get_site_notices( $network_level_or_blog_id ); + $notices->clear_all_sticky( $is_temporary ); + } + + if ( $this->_is_multisite && + ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) ) + ) { + $this->_network_notices->clear_all_sticky( $is_temporary ); + } + } + + /** + * Add admin message to all admin messages queue, and hook to all_admin_notices if not yet hooked. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.4 + * + * @param string $message + * @param string $title + * @param string $type + * @param bool $is_sticky + * @param string $id Message ID + */ + function add_all( $message, $title = '', $type = 'success', $is_sticky = false, $id = '' ) { + $this->add( $message, $title, $type, $is_sticky, true, $id ); + } + + #-------------------------------------------------------------------------------- + #region Helper Methods + #-------------------------------------------------------------------------------- + + /** + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + * + * @param int $blog_id + * + * @return FS_Admin_Notice_Manager + */ + private function get_site_notices( $blog_id = 0 ) { + if ( 0 == $blog_id || $blog_id == $this->_blog_id ) { + return $this->_notices; + } + + return FS_Admin_Notice_Manager::instance( + $this->_id, + $this->_title, + $this->_module_unique_affix, + false, + $blog_id + ); + } + + /** + * Check if the network notices should be used. + * + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + * + * @param string $id + * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite notices (if there's a network). When `false`, use the current context blog notices. When `null`, the decision which notices manager to use (MS vs. Current S) will be handled internally and determined based on the $id and the context admin (blog admin vs. network level admin). + * + * @return bool + */ + private function should_use_network_notices( $id = '', $network_level_or_blog_id = null ) { + if ( ! $this->_is_multisite ) { + // Not a multisite environment. + return false; + } + + if ( is_numeric( $network_level_or_blog_id ) ) { + // Explicitly asked to use a specified blog storage. + return false; + } + + if ( is_bool( $network_level_or_blog_id ) ) { + // Explicitly specified whether should use the network or blog level storage. + return $network_level_or_blog_id; + } + + return fs_is_network_admin(); + } + + /** + * Retrieves an instance of FS_Admin_Notice_Manager. + * + * @author Leo Fajardo (@leorw) + * @since 2.5.0 + * + * @param string $id + * @param int|null $network_level_or_blog_id + * + * @return FS_Admin_Notice_Manager + */ + private function get_site_or_network_notices( $id, $network_level_or_blog_id ) { + return $this->should_use_network_notices( $id, $network_level_or_blog_id ) ? + $this->_network_notices : + $this->get_site_notices( $network_level_or_blog_id ); + } + + #endregion }\ No newline at end of file
Vulnerability Existed: no Explanation: The diff shows only line ending changes (CRLF to LF conversion) across the entire file. There are no functional code changes, logic modifications, or security-related alterations. The code structure, methods, parameters, and implementation remain identical between versions 1.2.11 and 1.2.12. This is purely a formatting/normalization change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/class-fs-lock.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/class-fs-lock.php 2026-01-19 00:17:37.655045280 +0000@@ -1,110 +1,110 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.5.1- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Class FS_Lock- *- * @author Vova Feldman (@svovaf)- * @since 2.5.1- */- class FS_Lock {- /**- * @var int Random ID representing the current PHP thread.- */- private static $_thread_id;- /**- * @var string- */- private $_lock_id;-- /**- * @param string $lock_id- */- function __construct( $lock_id ) {- if ( ! fs_starts_with( $lock_id, WP_FS___OPTION_PREFIX ) ) {- $lock_id = WP_FS___OPTION_PREFIX . $lock_id;- }-- $this->_lock_id = $lock_id;-- if ( ! isset( self::$_thread_id ) ) {- self::$_thread_id = mt_rand( 0, 32000 );- }- }-- /**- * Try to acquire lock. If the lock is already set or is being acquired by another locker, don't do anything.- *- * @param int $expiration- *- * @return bool TRUE if successfully acquired lock.- */- function try_lock( $expiration = 0 ) {- if ( $this->is_locked() ) {- // Already locked.- return false;- }-- set_site_transient( $this->_lock_id, self::$_thread_id, $expiration );-- if ( $this->has_lock() ) {- $this->lock($expiration);-- return true;- }-- return false;- }-- /**- * Acquire lock regardless if it's already acquired by another locker or not.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @param int $expiration- */- function lock( $expiration = 0 ) {- set_site_transient( $this->_lock_id, true, $expiration );- }-- /**- * Checks if lock is currently acquired.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @return bool- */- function is_locked() {- return ( false !== get_site_transient( $this->_lock_id ) );- }-- /**- * Unlock the lock.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- */- function unlock() {- delete_site_transient( $this->_lock_id );- }-- /**- * Checks if lock is currently acquired by the current locker.- *- * @return bool- */- protected function has_lock() {- return ( self::$_thread_id == get_site_transient( $this->_lock_id ) );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.5.1 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Class FS_Lock + * + * @author Vova Feldman (@svovaf) + * @since 2.5.1 + */ + class FS_Lock { + /** + * @var int Random ID representing the current PHP thread. + */ + private static $_thread_id; + /** + * @var string + */ + private $_lock_id; + + /** + * @param string $lock_id + */ + function __construct( $lock_id ) { + if ( ! fs_starts_with( $lock_id, WP_FS___OPTION_PREFIX ) ) { + $lock_id = WP_FS___OPTION_PREFIX . $lock_id; + } + + $this->_lock_id = $lock_id; + + if ( ! isset( self::$_thread_id ) ) { + self::$_thread_id = mt_rand( 0, 32000 ); + } + } + + /** + * Try to acquire lock. If the lock is already set or is being acquired by another locker, don't do anything. + * + * @param int $expiration + * + * @return bool TRUE if successfully acquired lock. + */ + function try_lock( $expiration = 0 ) { + if ( $this->is_locked() ) { + // Already locked. + return false; + } + + set_site_transient( $this->_lock_id, self::$_thread_id, $expiration ); + + if ( $this->has_lock() ) { + $this->lock($expiration); + + return true; + } + + return false; + } + + /** + * Acquire lock regardless if it's already acquired by another locker or not. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @param int $expiration + */ + function lock( $expiration = 0 ) { + set_site_transient( $this->_lock_id, true, $expiration ); + } + + /** + * Checks if lock is currently acquired. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @return bool + */ + function is_locked() { + return ( false !== get_site_transient( $this->_lock_id ) ); + } + + /** + * Unlock the lock. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + */ + function unlock() { + delete_site_transient( $this->_lock_id ); + } + + /** + * Checks if lock is currently acquired by the current locker. + * + * @return bool + */ + protected function has_lock() { + return ( self::$_thread_id == get_site_transient( $this->_lock_id ) ); + } }\ No newline at end of file
Vulnerability Existed: no Analysis of Diff: The provided diff shows only a line-ending change (converting from Unix LF to Windows CRLF line endings, or vice versa). The actual code content remains identical between versions 1.2.11 and 1.2.12. Since there are no functional code changes in this diff, there are no new security fixes to analyze, and no vulnerabilities are introduced or removed. **Summary:** - No code logic was modified - No security-related changes were made - This appears to be a whitespace/line-ending normalization only
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/class-fs-logger.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/class-fs-logger.php 2026-01-19 00:17:37.655045280 +0000@@ -1,692 +1,692 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Logger {- private $_id;- private $_on = false;- private $_echo = false;- private $_file_start = 0;- /**- * @var int PHP Process ID.- */- private static $_processID;- /**- * @var string PHP Script user name.- */- private static $_ownerName;- /**- * @var bool Is storage logging turned on.- */- private static $_isStorageLoggingOn;- /**- * @var int ABSPATH length.- */- private static $_abspathLength;-- private static $LOGGERS = array();- private static $LOG = array();- private static $CNT = 0;- private static $_HOOKED_FOOTER = false;-- private function __construct( $id, $on = false, $echo = false ) {- $bt = debug_backtrace();-- $this->_id = $id;-- $caller = $bt[2];-- if ( false !== strpos( $caller['file'], 'plugins' ) ) {- $this->_file_start = strpos( $caller['file'], 'plugins' ) + strlen( 'plugins/' );- } else {- $this->_file_start = strpos( $caller['file'], 'themes' ) + strlen( 'themes/' );- }-- if ( $on ) {- $this->on();- }- if ( $echo ) {- $this->echo_on();- }- }-- /**- * @param string $id- * @param bool $on- * @param bool $echo- *- * @return FS_Logger- */- public static function get_logger( $id, $on = false, $echo = false ) {- $id = strtolower( $id );-- if ( ! isset( self::$_processID ) ) {- self::init();- }-- if ( ! isset( self::$LOGGERS[ $id ] ) ) {- self::$LOGGERS[ $id ] = new FS_Logger( $id, $on, $echo );- }-- return self::$LOGGERS[ $id ];- }-- /**- * Initialize logging global info.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- */- private static function init() {- self::$_ownerName = function_exists( 'get_current_user' ) ?- get_current_user() :- 'unknown';- self::$_isStorageLoggingOn = ( 1 == get_option( 'fs_storage_logger', 0 ) );- self::$_abspathLength = strlen( ABSPATH );- self::$_processID = mt_rand( 0, 32000 );-- // Process ID may be `false` on errors.- if ( ! is_numeric( self::$_processID ) ) {- self::$_processID = 0;- }- }-- private static function hook_footer() {- if ( self::$_HOOKED_FOOTER ) {- return;- }-- if ( is_admin() ) {- add_action( 'admin_footer', 'FS_Logger::dump', 100 );- } else {- add_action( 'wp_footer', 'FS_Logger::dump', 100 );- }- }-- function is_on() {- return $this->_on;- }-- function on() {- $this->_on = true;-- if ( ! function_exists( 'dbDelta' ) ) {- require_once ABSPATH . 'wp-admin/includes/upgrade.php';- }-- self::hook_footer();- }-- function echo_on() {- $this->on();-- $this->_echo = true;- }-- function is_echo_on() {- return $this->_echo;- }-- function get_id() {- return $this->_id;- }-- function get_file() {- return $this->_file_start;- }-- private function _log( &$message, $type, $wrapper = false ) {- if ( ! $this->is_on() ) {- return;- }-- $bt = debug_backtrace();- $depth = $wrapper ? 3 : 2;- while ( $depth < count( $bt ) - 1 && 'eval' === $bt[ $depth ]['function'] ) {- $depth ++;- }-- $caller = $bt[ $depth ];-- /**- * Retrieve the correct call file & line number from backtrace- * when logging from a wrapper method.- *- * @author Vova Feldman- * @since 1.2.1.6- */- if ( empty( $caller['line'] ) ) {- $depth --;-- while ( $depth >= 0 ) {- if ( ! empty( $bt[ $depth ]['line'] ) ) {- $caller['line'] = $bt[ $depth ]['line'];- $caller['file'] = $bt[ $depth ]['file'];- break;- }- }- }-- $log = array_merge( $caller, array(- 'cnt' => self::$CNT ++,- 'logger' => $this,- 'timestamp' => microtime( true ),- 'log_type' => $type,- 'msg' => $message,- ) );-- if ( self::$_isStorageLoggingOn ) {- $this->db_log( $type, $message, self::$CNT, $caller );- }-- self::$LOG[] = $log;-- if ( $this->is_echo_on() && ! Freemius::is_ajax() ) {- echo self::format_html( $log ) . "\n";- }- }-- function log( $message, $wrapper = false ) {- $this->_log( $message, 'log', $wrapper );- }-- function info( $message, $wrapper = false ) {- $this->_log( $message, 'info', $wrapper );- }-- function warn( $message, $wrapper = false ) {- $this->_log( $message, 'warn', $wrapper );- }-- function error( $message, $wrapper = false ) {- $this->_log( $message, 'error', $wrapper );- }-- /**- * Log API error.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.5- *- * @param mixed $api_result- * @param bool $wrapper- */- function api_error( $api_result, $wrapper = false ) {- $message = '';- if ( is_object( $api_result ) &&- ! empty( $api_result->error ) &&- ! empty( $api_result->error->message )- ) {- $message = $api_result->error->message;- } else if ( is_object( $api_result ) ) {- $message = var_export( $api_result, true );- } else if ( is_string( $api_result ) ) {- $message = $api_result;- } else if ( empty( $api_result ) ) {- $message = 'Empty API result.';- }-- $message = 'API Error: ' . $message;-- $this->_log( $message, 'error', $wrapper );- }-- function entrance( $message = '', $wrapper = false ) {- $msg = 'Entrance' . ( empty( $message ) ? '' : ' > ' ) . $message;-- $this->_log( $msg, 'log', $wrapper );- }-- function departure( $message = '', $wrapper = false ) {- $msg = 'Departure' . ( empty( $message ) ? '' : ' > ' ) . $message;-- $this->_log( $msg, 'log', $wrapper );- }-- #--------------------------------------------------------------------------------- #region Log Formatting- #---------------------------------------------------------------------------------- private static function format( $log, $show_type = true ) {- return '[' . str_pad( $log['cnt'], strlen( self::$CNT ), '0', STR_PAD_LEFT ) . '] [' . $log['logger']->_id . '] ' . ( $show_type ? '[' . $log['log_type'] . ']' : '' ) . ( ! empty( $log['class'] ) ? $log['class'] . $log['type'] : '' ) . $log['function'] . ' >> ' . $log['msg'] . ( isset( $log['file'] ) ? ' (' . substr( $log['file'], $log['logger']->_file_start ) . ' ' . $log['line'] . ') ' : '' ) . ' [' . $log['timestamp'] . ']';- }-- private static function format_html( $log ) {- return '<div style="font-size: 13px; font-family: monospace; color: #7da767; padding: 8px 3px; background: #000; border-bottom: 1px solid #555;">[' . $log['cnt'] . '] [' . $log['logger']->_id . '] [' . $log['log_type'] . '] <b><code style="color: #c4b1e0;">' . ( ! empty( $log['class'] ) ? $log['class'] . $log['type'] : '' ) . $log['function'] . '</code> >> <b style="color: #f59330;">' . esc_html( $log['msg'] ) . '</b></b>' . ( isset( $log['file'] ) ? ' (' . substr( $log['file'], $log['logger']->_file_start ) . ' ' . $log['line'] . ')' : '' ) . ' [' . $log['timestamp'] . ']</div>';- }-- #endregion-- static function dump() {- ?>- <!-- BEGIN: Freemius PHP Console Log -->- <script type="text/javascript">- <?php- foreach ( self::$LOG as $log ) {- echo 'console.' . $log['log_type'] . '(' . json_encode( self::format( $log, false ) ) . ')' . "\n";- }- ?>- </script>- <!-- END: Freemius PHP Console Log -->- <?php- }-- static function get_log() {- return self::$LOG;- }-- #--------------------------------------------------------------------------------- #region Database Logging- #---------------------------------------------------------------------------------- /**- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @return bool- */- public static function is_storage_logging_on() {- if ( ! isset( self::$_isStorageLoggingOn ) ) {- self::$_isStorageLoggingOn = ( 1 == get_option( 'fs_storage_logger', 0 ) );- }-- return self::$_isStorageLoggingOn;- }-- /**- * Turns on/off database persistent debugging to capture- * multi-session logs to debug complex flows like- * plugin auto-deactivate on premium version activation.- *- * @todo Check if Theme Check has issues with DB tables for themes.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @param bool $is_on- *- * @return bool- */- public static function _set_storage_logging( $is_on = true ) {- global $wpdb;-- $table = "{$wpdb->prefix}fs_logger";-- if ( $is_on ) {- /**- * Create logging table.- *- * NOTE:- * dbDelta must use KEY and not INDEX for indexes.- *- * @link https://core.trac.wordpress.org/ticket/2695- */- $result = $wpdb->query( "CREATE TABLE {$table} (-`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,-`process_id` INT UNSIGNED NOT NULL,-`user_name` VARCHAR(64) NOT NULL,-`logger` VARCHAR(128) NOT NULL,-`log_order` INT UNSIGNED NOT NULL,-`type` ENUM('log','info','warn','error') NOT NULL DEFAULT 'log',-`message` TEXT NOT NULL,-`file` VARCHAR(256) NOT NULL,-`line` INT UNSIGNED NOT NULL,-`function` VARCHAR(256) NOT NULL,-`request_type` ENUM('call','ajax','cron') NOT NULL DEFAULT 'call',-`request_url` VARCHAR(1024) NOT NULL,-`created` DECIMAL(16, 6) NOT NULL,-PRIMARY KEY (`id`),-KEY `process_id` (`process_id` ASC),-KEY `process_logger` (`process_id` ASC, `logger` ASC),-KEY `function` (`function` ASC),-KEY `type` (`type` ASC))" );- } else {- /**- * Drop logging table.- */- $result = $wpdb->query( "DROP TABLE IF EXISTS $table;" );- }-- if ( false !== $result ) {- update_option( 'fs_storage_logger', ( $is_on ? 1 : 0 ) );- }-- return ( false !== $result );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @param string $type- * @param string $message- * @param int $log_order- * @param array $caller- *- * @return false|int- */- private function db_log(- &$type,- &$message,- &$log_order,- &$caller- ) {- global $wpdb;-- $request_type = 'call';- if ( defined( 'DOING_CRON' ) && DOING_CRON ) {- $request_type = 'cron';- } else if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {- $request_type = 'ajax';- }-- $request_url = WP_FS__IS_HTTP_REQUEST ?- $_SERVER['REQUEST_URI'] :- '';-- return $wpdb->insert(- "{$wpdb->prefix}fs_logger",- array(- 'process_id' => self::$_processID,- 'user_name' => self::$_ownerName,- 'logger' => $this->_id,- 'log_order' => $log_order,- 'type' => $type,- 'request_type' => $request_type,- 'request_url' => $request_url,- 'message' => $message,- 'file' => isset( $caller['file'] ) ?- substr( $caller['file'], self::$_abspathLength ) :- '',- 'line' => $caller['line'],- 'function' => ( ! empty( $caller['class'] ) ? $caller['class'] . $caller['type'] : '' ) . $caller['function'],- 'created' => microtime( true ),- )- );- }-- /**- * Persistent DB logger columns.- *- * @var array- */- private static $_log_columns = array(- 'id',- 'process_id',- 'user_name',- 'logger',- 'log_order',- 'type',- 'message',- 'file',- 'line',- 'function',- 'request_type',- 'request_url',- 'created',- );-- /**- * Create DB logs query.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @param bool $filters- * @param int $limit- * @param int $offset- * @param bool $order- * @param bool $escape_eol- *- * @return string- */- private static function build_db_logs_query(- $filters = false,- $limit = 200,- $offset = 0,- $order = false,- $escape_eol = false- ) {- global $wpdb;-- $select = '*';-- if ( $escape_eol ) {- $select = '';- for ( $i = 0, $len = count( self::$_log_columns ); $i < $len; $i ++ ) {- if ( $i > 0 ) {- $select .= ', ';- }-- if ( 'message' !== self::$_log_columns[ $i ] ) {- $select .= self::$_log_columns[ $i ];- } else {- $select .= 'REPLACE(message , \'\n\', \' \') AS message';- }- }- }-- $query = "SELECT {$select} FROM {$wpdb->prefix}fs_logger";- if ( is_array( $filters ) ) {- $criteria = array();-- if ( ! empty( $filters['type'] ) && 'all' !== $filters['type'] ) {- $filters['type'] = strtolower( $filters['type'] );-- switch ( $filters['type'] ) {- case 'warn_error':- $criteria[] = array( 'col' => 'type', 'val' => array( 'warn', 'error' ) );- break;- case 'error':- case 'warn':- $criteria[] = array( 'col' => 'type', 'val' => $filters['type'] );- break;- case 'info':- default:- $criteria[] = array( 'col' => 'type', 'val' => array( 'info', 'log' ) );- break;- }- }-- if ( ! empty( $filters['request_type'] ) ) {- $filters['request_type'] = strtolower( $filters['request_type'] );-- if ( in_array( $filters['request_type'], array( 'call', 'ajax', 'cron' ) ) ) {- $criteria[] = array( 'col' => 'request_type', 'val' => $filters['request_type'] );- }- }-- if ( ! empty( $filters['file'] ) ) {- $criteria[] = array(- 'col' => 'file',- 'op' => 'LIKE',- 'val' => '%' . esc_sql( $filters['file'] ),- );- }-- if ( ! empty( $filters['function'] ) ) {- $criteria[] = array(- 'col' => 'function',- 'op' => 'LIKE',- 'val' => '%' . esc_sql( $filters['function'] ),- );- }-- if ( ! empty( $filters['process_id'] ) && is_numeric( $filters['process_id'] ) ) {- $criteria[] = array( 'col' => 'process_id', 'val' => $filters['process_id'] );- }-- if ( ! empty( $filters['logger'] ) ) {- $criteria[] = array(- 'col' => 'logger',- 'op' => 'LIKE',- 'val' => '%' . esc_sql( $filters['logger'] ) . '%',- );- }-- if ( ! empty( $filters['message'] ) ) {- $criteria[] = array(- 'col' => 'message',- 'op' => 'LIKE',- 'val' => '%' . esc_sql( $filters['message'] ) . '%',- );- }-- if ( 0 < count( $criteria ) ) {- $query .= "\nWHERE\n";-- $first = true;- foreach ( $criteria as $c ) {- if ( ! $first ) {- $query .= "AND\n";- }-- if ( is_array( $c['val'] ) ) {- $operator = 'IN';-- for ( $i = 0, $len = count( $c['val'] ); $i < $len; $i ++ ) {- $c['val'][ $i ] = "'" . esc_sql( $c['val'][ $i ] ) . "'";- }-- $val = '(' . implode( ',', $c['val'] ) . ')';- } else {- $operator = ! empty( $c['op'] ) ? $c['op'] : '=';- $val = "'" . esc_sql( $c['val'] ) . "'";- }-- $query .= "`{$c['col']}` {$operator} {$val}\n";-- $first = false;- }- }- }-- if ( ! is_array( $order ) ) {- $order = array(- 'col' => 'id',- 'order' => 'desc'- );- }-- $query .= " ORDER BY {$order['col']} {$order['order']} LIMIT {$offset},{$limit}";-- return $query;- }-- /**- * Load logs from DB.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @param bool $filters- * @param int $limit- * @param int $offset- * @param bool $order- *- * @return object[]|null- */- public static function load_db_logs(- $filters = false,- $limit = 200,- $offset = 0,- $order = false- ) {- global $wpdb;-- $query = self::build_db_logs_query(- $filters,- $limit,- $offset,- $order- );-- return $wpdb->get_results( $query );- }-- /**- * Load logs from DB.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @param bool $filters- * @param string $filename- * @param int $limit- * @param int $offset- * @param bool $order- *- * @return false|string File download URL or false on failure.- */- public static function download_db_logs(- $filters = false,- $filename = '',- $limit = 10000,- $offset = 0,- $order = false- ) {- global $wpdb;-- $query = self::build_db_logs_query(- $filters,- $limit,- $offset,- $order,- true- );-- $upload_dir = wp_upload_dir();- if ( empty( $filename ) ) {- $filename = 'fs-logs-' . date( 'Y-m-d_H-i-s', WP_FS__SCRIPT_START_TIME ) . '.csv';- }- $filepath = rtrim( $upload_dir['path'], '/' ) . "/{$filename}";-- $query .= " INTO OUTFILE '{$filepath}' FIELDS TERMINATED BY '\t' ESCAPED BY '\\\\' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\\n'";-- $columns = '';- for ( $i = 0, $len = count( self::$_log_columns ); $i < $len; $i ++ ) {- if ( $i > 0 ) {- $columns .= ', ';- }-- $columns .= "'" . self::$_log_columns[ $i ] . "'";- }-- $query = "SELECT {$columns} UNION ALL " . $query;-- $result = $wpdb->query( $query );-- if ( false === $result ) {- return false;- }-- return rtrim( $upload_dir['url'], '/' ) . '/' . $filename;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @param string $filename- *- * @return string- */- public static function get_logs_download_url( $filename = '' ) {- $upload_dir = wp_upload_dir();- if ( empty( $filename ) ) {- $filename = 'fs-logs-' . date( 'Y-m-d_H-i-s', WP_FS__SCRIPT_START_TIME ) . '.csv';- }-- return rtrim( $upload_dir['url'], '/' ) . $filename;- }-- #endregion- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Logger { + private $_id; + private $_on = false; + private $_echo = false; + private $_file_start = 0; + /** + * @var int PHP Process ID. + */ + private static $_processID; + /** + * @var string PHP Script user name. + */ + private static $_ownerName; + /** + * @var bool Is storage logging turned on. + */ + private static $_isStorageLoggingOn; + /** + * @var int ABSPATH length. + */ + private static $_abspathLength; + + private static $LOGGERS = array(); + private static $LOG = array(); + private static $CNT = 0; + private static $_HOOKED_FOOTER = false; + + private function __construct( $id, $on = false, $echo = false ) { + $bt = debug_backtrace(); + + $this->_id = $id; + + $caller = $bt[2]; + + if ( false !== strpos( $caller['file'], 'plugins' ) ) { + $this->_file_start = strpos( $caller['file'], 'plugins' ) + strlen( 'plugins/' ); + } else { + $this->_file_start = strpos( $caller['file'], 'themes' ) + strlen( 'themes/' ); + } + + if ( $on ) { + $this->on(); + } + if ( $echo ) { + $this->echo_on(); + } + } + + /** + * @param string $id + * @param bool $on + * @param bool $echo + * + * @return FS_Logger + */ + public static function get_logger( $id, $on = false, $echo = false ) { + $id = strtolower( $id ); + + if ( ! isset( self::$_processID ) ) { + self::init(); + } + + if ( ! isset( self::$LOGGERS[ $id ] ) ) { + self::$LOGGERS[ $id ] = new FS_Logger( $id, $on, $echo ); + } + + return self::$LOGGERS[ $id ]; + } + + /** + * Initialize logging global info. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.1.6 + */ + private static function init() { + self::$_ownerName = function_exists( 'get_current_user' ) ? + get_current_user() : + 'unknown'; + self::$_isStorageLoggingOn = ( 1 == get_option( 'fs_storage_logger', 0 ) ); + self::$_abspathLength = strlen( ABSPATH ); + self::$_processID = mt_rand( 0, 32000 ); + + // Process ID may be `false` on errors. + if ( ! is_numeric( self::$_processID ) ) { + self::$_processID = 0; + } + } + + private static function hook_footer() { + if ( self::$_HOOKED_FOOTER ) { + return; + } + + if ( is_admin() ) { + add_action( 'admin_footer', 'FS_Logger::dump', 100 ); + } else { + add_action( 'wp_footer', 'FS_Logger::dump', 100 ); + } + } + + function is_on() { + return $this->_on; + } + + function on() { + $this->_on = true; + + if ( ! function_exists( 'dbDelta' ) ) { + require_once ABSPATH . 'wp-admin/includes/upgrade.php'; + } + + self::hook_footer(); + } + + function echo_on() { + $this->on(); + + $this->_echo = true; + } + + function is_echo_on() { + return $this->_echo; + } + + function get_id() { + return $this->_id; + } + + function get_file() { + return $this->_file_start; + } + + private function _log( &$message, $type, $wrapper = false ) { + if ( ! $this->is_on() ) { + return; + } + + $bt = debug_backtrace(); + $depth = $wrapper ? 3 : 2; + while ( $depth < count( $bt ) - 1 && 'eval' === $bt[ $depth ]['function'] ) { + $depth ++; + } + + $caller = $bt[ $depth ]; + + /** + * Retrieve the correct call file & line number from backtrace + * when logging from a wrapper method. + * + * @author Vova Feldman + * @since 1.2.1.6 + */ + if ( empty( $caller['line'] ) ) { + $depth --; + + while ( $depth >= 0 ) { + if ( ! empty( $bt[ $depth ]['line'] ) ) { + $caller['line'] = $bt[ $depth ]['line']; + $caller['file'] = $bt[ $depth ]['file']; + break; + } + } + } + + $log = array_merge( $caller, array( + 'cnt' => self::$CNT ++, + 'logger' => $this, + 'timestamp' => microtime( true ), + 'log_type' => $type, + 'msg' => $message, + ) ); + + if ( self::$_isStorageLoggingOn ) { + $this->db_log( $type, $message, self::$CNT, $caller ); + } + + self::$LOG[] = $log; + + if ( $this->is_echo_on() && ! Freemius::is_ajax() ) { + echo self::format_html( $log ) . "\n"; + } + } + + function log( $message, $wrapper = false ) { + $this->_log( $message, 'log', $wrapper ); + } + + function info( $message, $wrapper = false ) { + $this->_log( $message, 'info', $wrapper ); + } + + function warn( $message, $wrapper = false ) { + $this->_log( $message, 'warn', $wrapper ); + } + + function error( $message, $wrapper = false ) { + $this->_log( $message, 'error', $wrapper ); + } + + /** + * Log API error. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.1.5 + * + * @param mixed $api_result + * @param bool $wrapper + */ + function api_error( $api_result, $wrapper = false ) { + $message = ''; + if ( is_object( $api_result ) && + ! empty( $api_result->error ) && + ! empty( $api_result->error->message ) + ) { + $message = $api_result->error->message; + } else if ( is_object( $api_result ) ) { + $message = var_export( $api_result, true ); + } else if ( is_string( $api_result ) ) { + $message = $api_result; + } else if ( empty( $api_result ) ) { + $message = 'Empty API result.'; + } + + $message = 'API Error: ' . $message; + + $this->_log( $message, 'error', $wrapper ); + } + + function entrance( $message = '', $wrapper = false ) { + $msg = 'Entrance' . ( empty( $message ) ? '' : ' > ' ) . $message; + + $this->_log( $msg, 'log', $wrapper ); + } + + function departure( $message = '', $wrapper = false ) { + $msg = 'Departure' . ( empty( $message ) ? '' : ' > ' ) . $message; + + $this->_log( $msg, 'log', $wrapper ); + } + + #-------------------------------------------------------------------------------- + #region Log Formatting + #-------------------------------------------------------------------------------- + + private static function format( $log, $show_type = true ) { + return '[' . str_pad( $log['cnt'], strlen( self::$CNT ), '0', STR_PAD_LEFT ) . '] [' . $log['logger']->_id . '] ' . ( $show_type ? '[' . $log['log_type'] . ']' : '' ) . ( ! empty( $log['class'] ) ? $log['class'] . $log['type'] : '' ) . $log['function'] . ' >> ' . $log['msg'] . ( isset( $log['file'] ) ? ' (' . substr( $log['file'], $log['logger']->_file_start ) . ' ' . $log['line'] . ') ' : '' ) . ' [' . $log['timestamp'] . ']'; + } + + private static function format_html( $log ) { + return '<div style="font-size: 13px; font-family: monospace; color: #7da767; padding: 8px 3px; background: #000; border-bottom: 1px solid #555;">[' . $log['cnt'] . '] [' . $log['logger']->_id . '] [' . $log['log_type'] . '] <b><code style="color: #c4b1e0;">' . ( ! empty( $log['class'] ) ? $log['class'] . $log['type'] : '' ) . $log['function'] . '</code> >> <b style="color: #f59330;">' . esc_html( $log['msg'] ) . '</b></b>' . ( isset( $log['file'] ) ? ' (' . substr( $log['file'], $log['logger']->_file_start ) . ' ' . $log['line'] . ')' : '' ) . ' [' . $log['timestamp'] . ']</div>'; + } + + #endregion + + static function dump() { + ?> + <!-- BEGIN: Freemius PHP Console Log --> + <script type="text/javascript"> + <?php + foreach ( self::$LOG as $log ) { + echo 'console.' . $log['log_type'] . '(' . json_encode( self::format( $log, false ) ) . ')' . "\n"; + } + ?> + </script> + <!-- END: Freemius PHP Console Log --> + <?php + } + + static function get_log() { + return self::$LOG; + } + + #-------------------------------------------------------------------------------- + #region Database Logging + #-------------------------------------------------------------------------------- + + /** + * @author Vova Feldman (@svovaf) + * @since 1.2.1.6 + * + * @return bool + */ + public static function is_storage_logging_on() { + if ( ! isset( self::$_isStorageLoggingOn ) ) { + self::$_isStorageLoggingOn = ( 1 == get_option( 'fs_storage_logger', 0 ) ); + } + + return self::$_isStorageLoggingOn; + } + + /** + * Turns on/off database persistent debugging to capture
I'll analyze this diff for security vulnerabilities.
Looking at the provided diff, this appears to be a line-ending change (Unix LF vs Windows CRLF) rather than a code logic change. The diff shows the entire file being replaced, but the actual content appears identical between versions 1.2.11 and 1.2.12.
Let me examine the actual code content for potential security issues:
**Vulnerability Analysis:**
Vulnerability Existed: yes
FALSE POSITIVE
SQL Injection - CWE-89 - inc/freemius/includes/class-fs-logger.php - Lines 369-413
[Old Code]
```php
$query .= " INTO OUTFILE '{$filepath}' FIELDS TERMINATED BY '\t' ESCAPED BY '\\\\' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\\n'";
```
[Fixed Code]
Same code (no fix detected in diff)
Explanation:
The `$filepath` variable is constructed from user-controllable input (`$filename` parameter) without proper escaping or validation before being used in a SQL query. While `$filename` has a default value, it can be passed as a parameter. If an attacker provides a malicious filename, they could break out of the `INTO OUTFILE` clause. However, this is mitigated by the fact that the path is constrained to the upload directory. This is a potential SQL injection vulnerability, though limited in scope.
---
Vulnerability Existed: not sure
Arbitrary File Write - CWE-434 - inc/freemius/includes/class-fs-logger.php - Lines 357-380
[Old Code]
```php
$filepath = rtrim( $upload_dir['path'], '/' ) . "/{$filename}";
```
[Fixed Code]
Same code (no fix detected in diff)
Explanation:
The `$filename` parameter is not validated or sanitized before being used in a file path. While it has a default value based on the current timestamp, if called with a user-supplied filename, path traversal attacks (e.g., `../../../etc/passwd`) could potentially be exploited to write files outside the intended upload directory. The use of `rtrim` and concatenation does not prevent directory traversal sequences like `../`.
---
**Summary:** The diff itself shows no changes to the code logic - only line-ending conversions. However, the existing code contains potential vulnerabilities in the `download_db_logs` function related to SQL injection and path traversal that were not fixed in this version update.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/class-fs-security.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/class-fs-security.php 2026-01-19 00:17:37.655045280 +0000@@ -1,85 +1,85 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- define( 'WP_FS__SECURITY_PARAMS_PREFIX', 's_' );-- /**- * Class FS_Security- */- class FS_Security {- /**- * @var FS_Security- * @since 1.0.3- */- private static $_instance;- /**- * @var FS_Logger- * @since 1.0.3- */- private static $_logger;-- /**- * @return \FS_Security- */- public static function instance() {- if ( ! isset( self::$_instance ) ) {- self::$_instance = new FS_Security();- self::$_logger = FS_Logger::get_logger(- WP_FS__SLUG,- WP_FS__DEBUG_SDK,- WP_FS__ECHO_DEBUG_SDK- );- }-- return self::$_instance;- }-- private function __construct() {- }-- /**- * @param \FS_Scope_Entity $entity- * @param int $timestamp- * @param string $action- *- * @return string- */- function get_secure_token( FS_Scope_Entity $entity, $timestamp, $action = '' ) {- return md5(- $timestamp .- $entity->id .- $entity->secret_key .- $entity->public_key .- $action- );- }-- /**- * @param \FS_Scope_Entity $entity- * @param int|bool $timestamp- * @param string $action- *- * @return array- */- function get_context_params( FS_Scope_Entity $entity, $timestamp = false, $action = '' ) {- if ( false === $timestamp ) {- $timestamp = time();- }-- return array(- 's_ctx_type' => $entity->get_type(),- 's_ctx_id' => $entity->id,- 's_ctx_ts' => $timestamp,- 's_ctx_secure' => $this->get_secure_token( $entity, $timestamp, $action ),- );- }- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + define( 'WP_FS__SECURITY_PARAMS_PREFIX', 's_' ); + + /** + * Class FS_Security + */ + class FS_Security { + /** + * @var FS_Security + * @since 1.0.3 + */ + private static $_instance; + /** + * @var FS_Logger + * @since 1.0.3 + */ + private static $_logger; + + /** + * @return \FS_Security + */ + public static function instance() { + if ( ! isset( self::$_instance ) ) { + self::$_instance = new FS_Security(); + self::$_logger = FS_Logger::get_logger( + WP_FS__SLUG, + WP_FS__DEBUG_SDK, + WP_FS__ECHO_DEBUG_SDK + ); + } + + return self::$_instance; + } + + private function __construct() { + } + + /** + * @param \FS_Scope_Entity $entity + * @param int $timestamp + * @param string $action + * + * @return string + */ + function get_secure_token( FS_Scope_Entity $entity, $timestamp, $action = '' ) { + return md5( + $timestamp . + $entity->id . + $entity->secret_key . + $entity->public_key . + $action + ); + } + + /** + * @param \FS_Scope_Entity $entity + * @param int|bool $timestamp + * @param string $action + * + * @return array + */ + function get_context_params( FS_Scope_Entity $entity, $timestamp = false, $action = '' ) { + if ( false === $timestamp ) { + $timestamp = time(); + } + + return array( + 's_ctx_type' => $entity->get_type(), + 's_ctx_id' => $entity->id, + 's_ctx_ts' => $timestamp, + 's_ctx_secure' => $this->get_secure_token( $entity, $timestamp, $action ), + ); + } + }
# Security Analysis Result **No vulnerabilities detected.** The diff provided shows only **whitespace/line ending changes** (converting from one line ending format to another, likely DOS to Unix line endings or similar). The actual code content remains identical across all 85 lines. **Details:** - **File:** inc/freemius/includes/class-fs-security.php - **Change Type:** Formatting only (no functional code changes) - **Security Impact:** None The underlying code itself contains a known cryptographic weakness (use of MD5 for token generation in `get_secure_token()` method at lines 57-63), but this is **pre-existing** and not introduced or fixed by this diff. Since the diff makes no changes to the actual code logic, it neither introduces nor remedies any security vulnerabilities.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/class-fs-user-lock.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/class-fs-user-lock.php 2026-01-19 00:17:37.655045280 +0000@@ -1,90 +1,90 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.1.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- require_once WP_FS__DIR_INCLUDES . '/class-fs-lock.php';-- /**- * Class FS_User_Lock- */- class FS_User_Lock {- /**- * @var FS_Lock- */- private $_lock;-- #--------------------------------------------------------------------------------- #region Singleton- #---------------------------------------------------------------------------------- /**- * @var FS_User_Lock- */- private static $_instance;-- /**- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @return FS_User_Lock- */- static function instance() {- if ( ! isset( self::$_instance ) ) {- self::$_instance = new self();- }-- return self::$_instance;- }-- #endregion-- private function __construct() {- $current_user_id = Freemius::get_current_wp_user_id();-- $this->_lock = new FS_Lock( "locked_{$current_user_id}" );- }-- /**- * Try to acquire lock. If the lock is already set or is being acquired by another locker, don't do anything.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @param int $expiration- *- * @return bool TRUE if successfully acquired lock.- */- function try_lock( $expiration = 0 ) {- return $this->_lock->try_lock( $expiration );- }-- /**- * Acquire lock regardless if it's already acquired by another locker or not.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @param int $expiration- */- function lock( $expiration = 0 ) {- $this->_lock->lock( $expiration );- }-- /**- * Unlock the lock.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- */- function unlock() {- $this->_lock->unlock();- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.1.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + require_once WP_FS__DIR_INCLUDES . '/class-fs-lock.php'; + + /** + * Class FS_User_Lock + */ + class FS_User_Lock { + /** + * @var FS_Lock + */ + private $_lock; + + #-------------------------------------------------------------------------------- + #region Singleton + #-------------------------------------------------------------------------------- + + /** + * @var FS_User_Lock + */ + private static $_instance; + + /** + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @return FS_User_Lock + */ + static function instance() { + if ( ! isset( self::$_instance ) ) { + self::$_instance = new self(); + } + + return self::$_instance; + } + + #endregion + + private function __construct() { + $current_user_id = Freemius::get_current_wp_user_id(); + + $this->_lock = new FS_Lock( "locked_{$current_user_id}" ); + } + + /** + * Try to acquire lock. If the lock is already set or is being acquired by another locker, don't do anything. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @param int $expiration + * + * @return bool TRUE if successfully acquired lock. + */ + function try_lock( $expiration = 0 ) { + return $this->_lock->try_lock( $expiration ); + } + + /** + * Acquire lock regardless if it's already acquired by another locker or not. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @param int $expiration + */ + function lock( $expiration = 0 ) { + $this->_lock->lock( $expiration ); + } + + /** + * Unlock the lock. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + */ + function unlock() { + $this->_lock->unlock(); + } }\ No newline at end of file
Vulnerability Existed: no No Vulnerabilities Detected - inc/freemius/includes/class-fs-user-lock.php Explanation: This diff contains only whitespace changes (line ending conversions from CRLF to LF). The actual code logic remains identical between versions 1.2.11 and 1.2.12. No security-relevant code modifications were made. The file structure, class definitions, method implementations, and functional logic are completely unchanged. This is a formatting/normalization update with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/customizer/class-fs-customizer-support-section.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/customizer/class-fs-customizer-support-section.php 2026-01-19 00:17:37.655045280 +0000@@ -1,102 +1,102 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.2.7- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Class Zerif_Customizer_Theme_Info_Main- *- * @since 1.0.0- * @access public- */- class FS_Customizer_Support_Section extends WP_Customize_Section {-- function __construct( $manager, $id, $args = array() ) {- $manager->register_section_type( 'FS_Customizer_Support_Section' );-- parent::__construct( $manager, $id, $args );- }-- /**- * The type of customize section being rendered.- *- * @since 1.0.0- * @access public- * @var string- */- public $type = 'freemius-support-section';-- /**- * @var Freemius- */- public $fs = null;-- /**- * Add custom parameters to pass to the JS via JSON.- *- * @since 1.0.0- */- public function json() {- $json = parent::json();-- $is_contact_visible = $this->fs->is_page_visible( 'contact' );- $is_support_visible = $this->fs->is_page_visible( 'support' );-- $json['theme_title'] = $this->fs->get_plugin_name();-- if ( $is_contact_visible && $is_support_visible ) {- $json['theme_title'] .= ' ' . $this->fs->get_text_inline( 'Support', 'support' );- }-- if ( $is_contact_visible ) {- $json['contact'] = array(- 'label' => $this->fs->get_text_inline( 'Contact Us', 'contact-us' ),- 'url' => $this->fs->contact_url(),- );- }-- if ( $is_support_visible ) {- $json['support'] = array(- 'label' => $this->fs->get_text_inline( 'Support Forum', 'support-forum' ),- 'url' => $this->fs->get_support_forum_url()- );- }-- return $json;- }-- /**- * Outputs the Underscore.js template.- *- * @since 1.0.0- */- protected function render_template() {- ?>- <li id="fs_customizer_support"- class="accordion-section control-section control-section-{{ data.type }} cannot-expand">- <h3 class="accordion-section-title">- <span>{{ data.theme_title }}</span>- <# if ( data.contact && data.support ) { #>- <div class="button-group">- <# } #>- <# if ( data.contact ) { #>- <a class="button" href="{{ data.contact.url }}" target="_blank" rel="noopener noreferrer">{{ data.contact.label }} </a>- <# } #>- <# if ( data.support ) { #>- <a class="button" href="{{ data.support.url }}" target="_blank" rel="noopener noreferrer">{{ data.support.label }} </a>- <# } #>- <# if ( data.contact && data.support ) { #>- </div>- <# } #>- </h3>- </li>- <?php- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.2.7 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Class Zerif_Customizer_Theme_Info_Main + * + * @since 1.0.0 + * @access public + */ + class FS_Customizer_Support_Section extends WP_Customize_Section { + + function __construct( $manager, $id, $args = array() ) { + $manager->register_section_type( 'FS_Customizer_Support_Section' ); + + parent::__construct( $manager, $id, $args ); + } + + /** + * The type of customize section being rendered. + * + * @since 1.0.0 + * @access public + * @var string + */ + public $type = 'freemius-support-section'; + + /** + * @var Freemius + */ + public $fs = null; + + /** + * Add custom parameters to pass to the JS via JSON. + * + * @since 1.0.0 + */ + public function json() { + $json = parent::json(); + + $is_contact_visible = $this->fs->is_page_visible( 'contact' ); + $is_support_visible = $this->fs->is_page_visible( 'support' ); + + $json['theme_title'] = $this->fs->get_plugin_name(); + + if ( $is_contact_visible && $is_support_visible ) { + $json['theme_title'] .= ' ' . $this->fs->get_text_inline( 'Support', 'support' ); + } + + if ( $is_contact_visible ) { + $json['contact'] = array( + 'label' => $this->fs->get_text_inline( 'Contact Us', 'contact-us' ), + 'url' => $this->fs->contact_url(), + ); + } + + if ( $is_support_visible ) { + $json['support'] = array( + 'label' => $this->fs->get_text_inline( 'Support Forum', 'support-forum' ), + 'url' => $this->fs->get_support_forum_url() + ); + } + + return $json; + } + + /** + * Outputs the Underscore.js template. + * + * @since 1.0.0 + */ + protected function render_template() { + ?> + <li id="fs_customizer_support" + class="accordion-section control-section control-section-{{ data.type }} cannot-expand"> + <h3 class="accordion-section-title"> + <span>{{ data.theme_title }}</span> + <# if ( data.contact && data.support ) { #> + <div class="button-group"> + <# } #> + <# if ( data.contact ) { #> + <a class="button" href="{{ data.contact.url }}" target="_blank" rel="noopener noreferrer">{{ data.contact.label }} </a> + <# } #> + <# if ( data.support ) { #> + <a class="button" href="{{ data.support.url }}" target="_blank" rel="noopener noreferrer">{{ data.support.label }} </a> + <# } #> + <# if ( data.contact && data.support ) { #> + </div> + <# } #> + </h3> + </li> + <?php + } }\ No newline at end of file
Vulnerability Existed: no No Security Vulnerabilities Detected - inc/freemius/includes/customizer/class-fs-customizer-support-section.php Explanation: This diff shows only line ending changes (CRLF to LF conversion) with no substantive code modifications. The file content remains functionally identical: - No new code has been introduced - No existing security controls have been removed - No input validation, sanitization, or escaping logic has changed - The template variables (`data.contact.url`, `data.support.url`, `data.theme_title`, `data.contact.label`, `data.support.label`) remain wrapped with Underscore.js template delimiters and maintain their existing context assumptions The links use `target="_blank"` and `rel="noopener noreferrer"` attributes, which are appropriate for external link handling. The code relies on upstream sanitization from the Freemius library methods (`contact_url()`, `get_support_forum_url()`, `get_text_inline()`, `get_plugin_name()`). Since no functional code changes occurred, no vulnerabilities were introduced or fixed in this update.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/customizer/class-fs-customizer-upsell-control.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/customizer/class-fs-customizer-upsell-control.php 2026-01-19 00:17:37.655045280 +0000@@ -1,161 +1,161 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.2.7- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Class FS_Customizer_Upsell_Control- */- class FS_Customizer_Upsell_Control extends WP_Customize_Control {-- /**- * Control type- *- * @var string control type- */- public $type = 'freemius-upsell-control';-- /**- * @var Freemius- */- public $fs = null;-- /**- * @param WP_Customize_Manager $manager the customize manager class.- * @param string $id id.- * @param array $args customizer manager parameters.- */- public function __construct( WP_Customize_Manager $manager, $id, array $args ) {- $manager->register_control_type( 'FS_Customizer_Upsell_Control' );-- parent::__construct( $manager, $id, $args );- }-- /**- * Enqueue resources for the control.- */- public function enqueue() {- fs_enqueue_local_style( 'fs_customizer', 'customizer.css' );- }-- /**- * Json conversion- */- public function to_json() {- $pricing_cta = esc_html( $this->fs->get_pricing_cta_label() ) . ' ' . ( is_rtl() ? '←' : '➤' );-- parent::to_json();-- $this->json['button_text'] = $pricing_cta;- $this->json['button_url'] = $this->fs->is_in_trial_promotion() ?- $this->fs->get_trial_url() :- $this->fs->get_upgrade_url();-- $api = FS_Plugin::is_valid_id( $this->fs->get_bundle_id() ) ?- $this->fs->get_api_bundle_scope() :- $this->fs->get_api_plugin_scope();-- // Load features.- $pricing = $api->get( $this->fs->add_show_pending( "pricing.json" ) );-- if ( $this->fs->is_api_result_object( $pricing, 'plans' ) ) {- // Add support features.- if ( is_array( $pricing->plans ) && 0 < count( $pricing->plans ) ) {- $support_features = array(- 'kb' => 'Help Center',- 'forum' => 'Support Forum',- 'email' => 'Priority Email Support',- 'phone' => 'Phone Support',- 'skype' => 'Skype Support',- 'is_success_manager' => 'Personal Success Manager',- );-- for ( $i = 0, $len = count( $pricing->plans ); $i < $len; $i ++ ) {- if ( 'free' == $pricing->plans[$i]->name ) {- continue;- }-- if ( ! isset( $pricing->plans[ $i ]->features ) ||- ! is_array( $pricing->plans[ $i ]->features ) ) {- $pricing->plans[$i]->features = array();- }-- foreach ( $support_features as $key => $label ) {- $key = ( 'is_success_manager' !== $key ) ?- "support_{$key}" :- $key;-- if ( ! empty( $pricing->plans[ $i ]->{$key} ) ) {-- $support_feature = new stdClass();- $support_feature->title = $label;-- $pricing->plans[ $i ]->features[] = $support_feature;- }- }- }-- $this->json['plans'] = $pricing->plans;- }- }-- $this->json['strings'] = array(- 'plan' => $this->fs->get_text_x_inline( 'Plan', 'as product pricing plan', 'plan' ),- );- }-- /**- * Control content- */- public function content_template() {- ?>- <div id="fs_customizer_upsell">- <# if ( data.plans ) { #>- <ul class="fs-customizer-plans">- <# for (i in data.plans) { #>- <# if ( 'free' != data.plans[i].name && (null != data.plans[i].features && 0 < data.plans[i].features.length) ) { #>- <li class="fs-customizer-plan">- <div class="fs-accordion-section-open">- <h2 class="fs-accordion-section-title menu-item">- <span>{{ data.plans[i].title }}</span>- <button type="button" class="button-link item-edit" aria-expanded="true">- <span class="screen-reader-text">Toggle section: {{ data.plans[i].title }} {{ data.strings.plan }}</span>- <span class="toggle-indicator" aria-hidden="true"></span>- </button>- </h2>- <div class="fs-accordion-section-content">- <# if ( data.plans[i].description ) { #>- <h3>{{ data.plans[i].description }}</h3>- <# } #>- <# if ( data.plans[i].features ) { #>- <ul>- <# for ( j in data.plans[i].features ) { #>- <li><div class="fs-feature">- <span class="dashicons dashicons-yes"></span><span><# if ( data.plans[i].features[j].value ) { #>{{ data.plans[i].features[j].value }} <# } #>{{ data.plans[i].features[j].title }}</span>- <# if ( data.plans[i].features[j].description ) { #>- <span class="dashicons dashicons-editor-help"><span class="fs-feature-desc">{{ data.plans[i].features[j].description }}</span></span>- <# } #>- </div></li>- <# } #>- </ul>- <# } #>- <# if ( 'free' != data.plans[i].name ) { #>- <a href="{{ data.button_url }}" class="button button-primary" target="_blank">{{{ data.button_text }}}</a>- <# } #>- </div>- </div>- </li>- <# } #>- <# } #>- </ul>- <# } #>- </div>- <?php }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.2.7 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Class FS_Customizer_Upsell_Control + */ + class FS_Customizer_Upsell_Control extends WP_Customize_Control { + + /** + * Control type + * + * @var string control type + */ + public $type = 'freemius-upsell-control'; + + /** + * @var Freemius + */ + public $fs = null; + + /** + * @param WP_Customize_Manager $manager the customize manager class. + * @param string $id id. + * @param array $args customizer manager parameters. + */ + public function __construct( WP_Customize_Manager $manager, $id, array $args ) { + $manager->register_control_type( 'FS_Customizer_Upsell_Control' ); + + parent::__construct( $manager, $id, $args ); + } + + /** + * Enqueue resources for the control. + */ + public function enqueue() { + fs_enqueue_local_style( 'fs_customizer', 'customizer.css' ); + } + + /** + * Json conversion + */ + public function to_json() { + $pricing_cta = esc_html( $this->fs->get_pricing_cta_label() ) . ' ' . ( is_rtl() ? '←' : '➤' ); + + parent::to_json(); + + $this->json['button_text'] = $pricing_cta; + $this->json['button_url'] = $this->fs->is_in_trial_promotion() ? + $this->fs->get_trial_url() : + $this->fs->get_upgrade_url(); + + $api = FS_Plugin::is_valid_id( $this->fs->get_bundle_id() ) ? + $this->fs->get_api_bundle_scope() : + $this->fs->get_api_plugin_scope(); + + // Load features. + $pricing = $api->get( $this->fs->add_show_pending( "pricing.json" ) ); + + if ( $this->fs->is_api_result_object( $pricing, 'plans' ) ) { + // Add support features. + if ( is_array( $pricing->plans ) && 0 < count( $pricing->plans ) ) { + $support_features = array( + 'kb' => 'Help Center', + 'forum' => 'Support Forum', + 'email' => 'Priority Email Support', + 'phone' => 'Phone Support', + 'skype' => 'Skype Support', + 'is_success_manager' => 'Personal Success Manager', + ); + + for ( $i = 0, $len = count( $pricing->plans ); $i < $len; $i ++ ) { + if ( 'free' == $pricing->plans[$i]->name ) { + continue; + } + + if ( ! isset( $pricing->plans[ $i ]->features ) || + ! is_array( $pricing->plans[ $i ]->features ) ) { + $pricing->plans[$i]->features = array(); + } + + foreach ( $support_features as $key => $label ) { + $key = ( 'is_success_manager' !== $key ) ? + "support_{$key}" : + $key; + + if ( ! empty( $pricing->plans[ $i ]->{$key} ) ) { + + $support_feature = new stdClass(); + $support_feature->title = $label; + + $pricing->plans[ $i ]->features[] = $support_feature; + } + } + } + + $this->json['plans'] = $pricing->plans; + } + } + + $this->json['strings'] = array( + 'plan' => $this->fs->get_text_x_inline( 'Plan', 'as product pricing plan', 'plan' ), + ); + } + + /** + * Control content + */ + public function content_template() { + ?> + <div id="fs_customizer_upsell"> + <# if ( data.plans ) { #> + <ul class="fs-customizer-plans"> + <# for (i in data.plans) { #> + <# if ( 'free' != data.plans[i].name && (null != data.plans[i].features && 0 < data.plans[i].features.length) ) { #> + <li class="fs-customizer-plan"> + <div class="fs-accordion-section-open"> + <h2 class="fs-accordion-section-title menu-item"> + <span>{{ data.plans[i].title }}</span> + <button type="button" class="button-link item-edit" aria-expanded="true"> + <span class="screen-reader-text">Toggle section: {{ data.plans[i].title }} {{ data.strings.plan }}</span> + <span class="toggle-indicator" aria-hidden="true"></span> + </button> + </h2> + <div class="fs-accordion-section-content"> + <# if ( data.plans[i].description ) { #> + <h3>{{ data.plans[i].description }}</h3> + <# } #> + <# if ( data.plans[i].features ) { #> + <ul> + <# for ( j in data.plans[i].features ) { #> + <li><div class="fs-feature"> + <span class="dashicons dashicons-yes"></span><span><# if ( data.plans[i].features[j].value ) { #>{{ data.plans[i].features[j].value }} <# } #>{{ data.plans[i].features[j].title }}</span> + <# if ( data.plans[i].features[j].description ) { #> + <span class="dashicons dashicons-editor-help"><span class="fs-feature-desc">{{ data.plans[i].features[j].description }}</span></span> + <# } #> + </div></li> + <# } #> + </ul> + <# } #> + <# if ( 'free' != data.plans[i].name ) { #> + <a href="{{ data.button_url }}" class="button button-primary" target="_blank">{{{ data.button_text }}}</a> + <# } #> + </div> + </div> + </li> + <# } #> + <# } #> + </ul> + <# } #> + </div> + <?php } }\ No newline at end of file
Vulnerability Existed: no Explanation: This diff contains only whitespace and line ending changes (CRLF to LF conversion). The actual code logic remains identical between versions 1.2.11 and 1.2.12. There are no functional code modifications, no new security vulnerabilities introduced, and no existing vulnerabilities fixed. The file structure, class definitions, methods, and all logic remain unchanged.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/customizer/index.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/customizer/index.php 2026-01-19 00:17:37.655045280 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No CWE Identified - File: inc/freemius/includes/customizer/index.php Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace changes (line ending normalization, likely converting between different line ending formats such as CRLF to LF or vice versa). No security vulnerabilities are introduced or fixed. The file remains an empty PHP file with comments, which is a standard security practice to prevent directory listing. No code logic, functionality, or security-relevant content has been modified.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/debug/class-fs-debug-bar-panel.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/debug/class-fs-debug-bar-panel.php 2026-01-19 00:17:37.655045280 +0000@@ -1,68 +1,68 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.7.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- if ( class_exists( 'Debug_Bar_Panel' ) ) {-- /**- * Extends Debug Bar plugin by adding a panel to show all Freemius API requests.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.7.3- *- * Class Freemius_Debug_Bar_Panel- */- class Freemius_Debug_Bar_Panel extends Debug_Bar_Panel {-- public function init() {- $this->title( 'Freemius' ); // @phpstan-ignore-line- }-- public static function requests_count() {- if ( class_exists( 'Freemius_Api_WordPress' ) ) {- $logger = Freemius_Api_WordPress::GetLogger();- } else {- $logger = array();- }-- return number_format( count( $logger ) );- }-- public static function total_time() {- if ( class_exists( 'Freemius_Api_WordPress' ) ) {- $logger = Freemius_Api_WordPress::GetLogger();- } else {- $logger = array();- }-- $total_time = .0;- foreach ( $logger as $l ) {- $total_time += $l['total'];- }-- return number_format( 100 * $total_time, 2 ) . ' ' . fs_text_x_inline( 'ms', 'milliseconds' );- }-- public function render() {- ?>- <div id='debug-bar-php'>- <?php fs_require_template( '/debug/api-calls.php' ) ?>- <br>- <?php fs_require_template( '/debug/scheduled-crons.php' ) ?>- <br>- <?php fs_require_template( '/debug/plugins-themes-sync.php' ) ?>- <br>- <?php fs_require_template( '/debug/logger.php' ) ?>- </div>- <?php- }- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.7.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + if ( class_exists( 'Debug_Bar_Panel' ) ) { + + /** + * Extends Debug Bar plugin by adding a panel to show all Freemius API requests. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.7.3 + * + * Class Freemius_Debug_Bar_Panel + */ + class Freemius_Debug_Bar_Panel extends Debug_Bar_Panel { + + public function init() { + $this->title( 'Freemius' ); // @phpstan-ignore-line + } + + public static function requests_count() { + if ( class_exists( 'Freemius_Api_WordPress' ) ) { + $logger = Freemius_Api_WordPress::GetLogger(); + } else { + $logger = array(); + } + + return number_format( count( $logger ) ); + } + + public static function total_time() { + if ( class_exists( 'Freemius_Api_WordPress' ) ) { + $logger = Freemius_Api_WordPress::GetLogger(); + } else { + $logger = array(); + } + + $total_time = .0; + foreach ( $logger as $l ) { + $total_time += $l['total']; + } + + return number_format( 100 * $total_time, 2 ) . ' ' . fs_text_x_inline( 'ms', 'milliseconds' ); + } + + public function render() { + ?> + <div id='debug-bar-php'> + <?php fs_require_template( '/debug/api-calls.php' ) ?> + <br> + <?php fs_require_template( '/debug/scheduled-crons.php' ) ?> + <br> + <?php fs_require_template( '/debug/plugins-themes-sync.php' ) ?> + <br> + <?php fs_require_template( '/debug/logger.php' ) ?> + </div> + <?php + } + } }\ No newline at end of file
Vulnerability Existed: no Explanation: This diff shows only whitespace/line ending changes (converting from Unix line endings to Windows line endings or vice versa). The actual code content remains identical between versions 1.2.11 and 1.2.12. No security-relevant code modifications were made, no new vulnerabilities were introduced, and no existing vulnerabilities were fixed. The file structure, logic, functions, and security posture remain completely unchanged.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/debug/debug-bar-start.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/debug/debug-bar-start.php 2026-01-19 00:17:37.655045280 +0000@@ -1,52 +1,52 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.7.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- if ( ! WP_FS__DEBUG_SDK ) {- return;- }-- /**- * Initialize Freemius custom debug panels.- *- * @param array $panels Debug bar panels objects- *- * @return array Debug bar panels with your custom panels- */- function fs_custom_panels_init( $panels ) {- if ( class_exists( 'Debug_Bar_Panel' ) ) {- if ( FS_API__LOGGER_ON ) {- require_once dirname( __FILE__ ) . '/class-fs-debug-bar-panel.php';- $panels[] = new Freemius_Debug_Bar_Panel();- }- }-- return $panels;- }-- function fs_custom_status_init( $statuses ) {- if ( class_exists( 'Debug_Bar_Panel' ) ) {- if ( FS_API__LOGGER_ON ) {- require_once dirname( __FILE__ ) . '/class-fs-debug-bar-panel.php';- $statuses[] = array(- 'fs_api_requests',- fs_text_inline( 'Freemius API' ),- Freemius_Debug_Bar_Panel::requests_count() . ' ' . fs_text_inline( 'Requests' ) .- ' (' . Freemius_Debug_Bar_Panel::total_time() . ')'- );- }- }-- return $statuses;- }-- add_filter( 'debug_bar_panels', 'fs_custom_panels_init' );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.7.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + if ( ! WP_FS__DEBUG_SDK ) { + return; + } + + /** + * Initialize Freemius custom debug panels. + * + * @param array $panels Debug bar panels objects + * + * @return array Debug bar panels with your custom panels + */ + function fs_custom_panels_init( $panels ) { + if ( class_exists( 'Debug_Bar_Panel' ) ) { + if ( FS_API__LOGGER_ON ) { + require_once dirname( __FILE__ ) . '/class-fs-debug-bar-panel.php'; + $panels[] = new Freemius_Debug_Bar_Panel(); + } + } + + return $panels; + } + + function fs_custom_status_init( $statuses ) { + if ( class_exists( 'Debug_Bar_Panel' ) ) { + if ( FS_API__LOGGER_ON ) { + require_once dirname( __FILE__ ) . '/class-fs-debug-bar-panel.php'; + $statuses[] = array( + 'fs_api_requests', + fs_text_inline( 'Freemius API' ), + Freemius_Debug_Bar_Panel::requests_count() . ' ' . fs_text_inline( 'Requests' ) . + ' (' . Freemius_Debug_Bar_Panel::total_time() . ')' + ); + } + } + + return $statuses; + } + + add_filter( 'debug_bar_panels', 'fs_custom_panels_init' ); add_filter( 'debug_bar_statuses', 'fs_custom_status_init' );\ No newline at end of file
Vulnerability Existed: no
No Security Vulnerabilities Detected - [N/A] - inc/freemius/includes/debug/debug-bar-start.php [All lines]
[Old Code]
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.1.7.3
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! WP_FS__DEBUG_SDK ) {
return;
}
// ... rest of file
```
[Fixed Code]
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.1.7.3
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! WP_FS__DEBUG_SDK ) {
return;
}
// ... rest of file
```
Explanation:
This diff represents a line-ending normalization change (CRLF to LF conversion). The actual code logic remains identical between versions 1.2.11 and 1.2.12. No security-related modifications, input validation changes, access control updates, or vulnerability patches are present. The file contains properly guarded includes with `dirname( __FILE__ )` and appropriate WordPress hooks. No new vulnerabilities were introduced, and no existing vulnerabilities were fixed in this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/debug/index.php 2026-01-19 00:16:00.445014692 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/debug/index.php 2026-01-19 00:17:37.655045280 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Vulnerabilities Detected - inc/freemius/includes/debug/index.php Explanation: The diff shows only whitespace/formatting changes (line ending normalization from CRLF to LF or similar). The file content remains functionally identical: - Line 1: `<?php` opening tag (unchanged) - Line 2: Comment `// Silence is golden.` (unchanged) - Line 3: Comment about hiding file structure (unchanged) This is an index.php file with no executable code, only comments. It serves as a file structure hiding mechanism on unprotected servers (a common WordPress security practice). The changes are purely formatting and introduce no new vulnerabilities nor fix any existing ones.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-affiliate-terms.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-affiliate-terms.php 2026-01-19 00:17:37.655045280 +0000@@ -1,132 +1,132 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_AffiliateTerms extends FS_Scope_Entity {-- #region Properties-- /**- * @var bool- */- public $is_active;- /**- * @var string Enum: `affiliation` or `rewards`. Defaults to `affiliation`.- */- public $type;- /**- * @var string Enum: `payout` or `credit`. Defaults to `payout`.- */- public $reward_type;- /**- * If `first`, the referral will be attributed to the first visited source containing the affiliation link that- * was clicked.- *- * @var string Enum: `first` or `last`. Defaults to `first`.- */- public $referral_attribution;- /**- * @var int Defaults to `30`, `0` for session cookie, and `null` for endless cookie (until cookies are cleaned).- */- public $cookie_days;- /**- * @var int- */- public $commission;- /**- * @var string Enum: `percentage` or `dollar`. Defaults to `percentage`.- */- public $commission_type;- /**- * @var null|int Defaults to `0` (affiliate only on first payment). `null` for commission for all renewals. If- * greater than `0`, affiliate will get paid for all renewals for `commission_renewals_days` days after- * the initial upgrade/purchase.- */- public $commission_renewals_days;- /**- * @var int Only cents and no percentage. In US cents, e.g.: 100 = $1.00. Defaults to `null`.- */- public $install_commission;- /**- * @var string Required default target link, e.g.: pricing page.- */- public $default_url;- /**- * @var string One of the following: 'all', 'new_customer', 'new_user'.- * If 'all' - reward for any user type.- * If 'new_customer' - reward only for new customers.- * If 'new_user' - reward only for new users.- */- public $reward_customer_type;- /**- * @var int Defaults to `0` (affiliate only on directly affiliated links). `null` if an affiliate will get- * paid for all customers' lifetime payments. If greater than `0`, an affiliate will get paid for all- * customer payments for `future_payments_days` days after the initial payment.- */- public $future_payments_days;- /**- * @var bool If `true`, allow referrals from social sites.- */- public $is_social_allowed;- /**- * @var bool If `true`, allow conversions without HTTP referrer header at all.- */- public $is_app_allowed;- /**- * @var bool If `true`, allow referrals from any site.- */- public $is_any_site_allowed;- /**- * @var string $plugin_title Title of the plugin. This is used in case we are showing affiliate form for a Bundle instead of the `plugin` in context.- */- public $plugin_title;-- #endregion Properties-- /**- * @author Leo Fajardo (@leorw)- *- * @return string- */- function get_formatted_commission()- {- return ( 'dollar' === $this->commission_type ) ?- ( '$' . $this->commission ) :- ( $this->commission . '%' );- }-- /**- * @author Leo Fajardo (@leorw)- *- * @return bool- */- function has_lifetime_commission() {- return ( 0 !== $this->future_payments_days );- }-- /**- * @author Leo Fajardo (@leorw)- *- * @return bool- */- function is_session_cookie() {- return ( 0 == $this->cookie_days );- }-- /**- * @author Leo Fajardo (@leorw)- *- * @return bool- */- function has_renewals_commission() {- return ( is_null( $this->commission_renewals_days ) || $this->commission_renewals_days > 0 );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_AffiliateTerms extends FS_Scope_Entity { + + #region Properties + + /** + * @var bool + */ + public $is_active; + /** + * @var string Enum: `affiliation` or `rewards`. Defaults to `affiliation`. + */ + public $type; + /** + * @var string Enum: `payout` or `credit`. Defaults to `payout`. + */ + public $reward_type; + /** + * If `first`, the referral will be attributed to the first visited source containing the affiliation link that + * was clicked. + * + * @var string Enum: `first` or `last`. Defaults to `first`. + */ + public $referral_attribution; + /** + * @var int Defaults to `30`, `0` for session cookie, and `null` for endless cookie (until cookies are cleaned). + */ + public $cookie_days; + /** + * @var int + */ + public $commission; + /** + * @var string Enum: `percentage` or `dollar`. Defaults to `percentage`. + */ + public $commission_type; + /** + * @var null|int Defaults to `0` (affiliate only on first payment). `null` for commission for all renewals. If + * greater than `0`, affiliate will get paid for all renewals for `commission_renewals_days` days after + * the initial upgrade/purchase. + */ + public $commission_renewals_days; + /** + * @var int Only cents and no percentage. In US cents, e.g.: 100 = $1.00. Defaults to `null`. + */ + public $install_commission; + /** + * @var string Required default target link, e.g.: pricing page. + */ + public $default_url; + /** + * @var string One of the following: 'all', 'new_customer', 'new_user'. + * If 'all' - reward for any user type. + * If 'new_customer' - reward only for new customers. + * If 'new_user' - reward only for new users. + */ + public $reward_customer_type; + /** + * @var int Defaults to `0` (affiliate only on directly affiliated links). `null` if an affiliate will get + * paid for all customers' lifetime payments. If greater than `0`, an affiliate will get paid for all + * customer payments for `future_payments_days` days after the initial payment. + */ + public $future_payments_days; + /** + * @var bool If `true`, allow referrals from social sites. + */ + public $is_social_allowed; + /** + * @var bool If `true`, allow conversions without HTTP referrer header at all. + */ + public $is_app_allowed; + /** + * @var bool If `true`, allow referrals from any site. + */ + public $is_any_site_allowed; + /** + * @var string $plugin_title Title of the plugin. This is used in case we are showing affiliate form for a Bundle instead of the `plugin` in context. + */ + public $plugin_title; + + #endregion Properties + + /** + * @author Leo Fajardo (@leorw) + * + * @return string + */ + function get_formatted_commission() + { + return ( 'dollar' === $this->commission_type ) ? + ( '$' . $this->commission ) : + ( $this->commission . '%' ); + } + + /** + * @author Leo Fajardo (@leorw) + * + * @return bool + */ + function has_lifetime_commission() { + return ( 0 !== $this->future_payments_days ); + } + + /** + * @author Leo Fajardo (@leorw) + * + * @return bool + */ + function is_session_cookie() { + return ( 0 == $this->cookie_days ); + } + + /** + * @author Leo Fajardo (@leorw) + * + * @return bool + */ + function has_renewals_commission() { + return ( is_null( $this->commission_renewals_days ) || $this->commission_renewals_days > 0 ); + } }\ No newline at end of file
Vulnerability Existed: no Explanation: This diff shows only a line ending change from Unix (LF) to Windows (CRLF) format across the entire file. The actual code content remains identical - no functional changes, logic modifications, or security-related code alterations were made. The file structure, class definition, properties, and methods are all unchanged. Since there are no code changes, there are no security vulnerabilities being fixed or introduced in this diff. This is purely a formatting/encoding change that has no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-affiliate.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-affiliate.php 2026-01-19 00:17:37.655045280 +0000@@ -1,84 +1,84 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Affiliate extends FS_Scope_Entity {-- #region Properties-- /**- * @var string- */- public $paypal_email;- /**- * @var number- */- public $custom_affiliate_terms_id;- /**- * @var boolean- */- public $is_using_custom_terms;- /**- * @var string status Enum: `pending`, `rejected`, `suspended`, or `active`. Defaults to `pending`.- */- public $status;- /**- * @var string- */- public $domain;-- #endregion Properties-- /**- * @author Leo Fajardo- *- * @return bool- */- function is_active() {- return ( 'active' === $this->status );- }-- /**- * @author Leo Fajardo- *- * @return bool- */- function is_pending() {- return ( 'pending' === $this->status );- }-- /**- * @author Leo Fajardo- *- * @return bool- */- function is_suspended() {- return ( 'suspended' === $this->status );- }-- /**- * @author Leo Fajardo- *- * @return bool- */- function is_rejected() {- return ( 'rejected' === $this->status );- }-- /**- * @author Leo Fajardo- *- * @return bool- */- function is_blocked() {- return ( 'blocked' === $this->status );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Affiliate extends FS_Scope_Entity { + + #region Properties + + /** + * @var string + */ + public $paypal_email; + /** + * @var number + */ + public $custom_affiliate_terms_id; + /** + * @var boolean + */ + public $is_using_custom_terms; + /** + * @var string status Enum: `pending`, `rejected`, `suspended`, or `active`. Defaults to `pending`. + */ + public $status; + /** + * @var string + */ + public $domain; + + #endregion Properties + + /** + * @author Leo Fajardo + * + * @return bool + */ + function is_active() { + return ( 'active' === $this->status ); + } + + /** + * @author Leo Fajardo + * + * @return bool + */ + function is_pending() { + return ( 'pending' === $this->status ); + } + + /** + * @author Leo Fajardo + * + * @return bool + */ + function is_suspended() { + return ( 'suspended' === $this->status ); + } + + /** + * @author Leo Fajardo + * + * @return bool + */ + function is_rejected() { + return ( 'rejected' === $this->status ); + } + + /** + * @author Leo Fajardo + * + * @return bool + */ + function is_blocked() { + return ( 'blocked' === $this->status ); + } }\ No newline at end of file
Vulnerability Existed: no No Security Vulnerabilities Detected - inc/freemius/includes/entities/class-fs-affiliate.php Explanation: This diff shows only line ending changes (CRLF to LF conversion), with no functional code modifications. The file content remains identical: - All class properties and methods are unchanged - No logic modifications that could introduce or fix vulnerabilities - No input handling, output encoding, authentication, or authorization changes - The file maintains its original structure and functionality This is a formatting-only change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-billing.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-billing.php 2026-01-19 00:17:37.655045280 +0000@@ -1,95 +1,95 @@-<?php- /**- * @package Freemius for EDD Add-On- * @copyright Copyright (c) 2016, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Billing extends FS_Entity {-- #region Properties-- /**- * @var int- */- public $entity_id;- /**- * @var string (Enum) Linked entity type. One of: developer, plugin, user, install- */- public $entity_type;- /**- * @var string- */- public $business_name;- /**- * @var string- */- public $first;- /**- * @var string- */- public $last;- /**- * @var string- */- public $email;- /**- * @var string- */- public $phone;- /**- * @var string- */- public $website;- /**- * @var string Tax or VAT ID.- */- public $tax_id;- /**- * @var string- */- public $address_street;- /**- * @var string- */- public $address_apt;- /**- * @var string- */- public $address_city;- /**- * @var string- */- public $address_country;- /**- * @var string Two chars country code.- */- public $address_country_code;- /**- * @var string- */- public $address_state;- /**- * @var number Numeric ZIP code (cab be with leading zeros).- */- public $address_zip;-- #endregion Properties--- /**- * @param object|bool $event- */- function __construct( $event = false ) {- parent::__construct( $event );- }-- static function get_type() {- return 'billing';- }+<?php + /** + * @package Freemius for EDD Add-On + * @copyright Copyright (c) 2016, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Billing extends FS_Entity { + + #region Properties + + /** + * @var int + */ + public $entity_id; + /** + * @var string (Enum) Linked entity type. One of: developer, plugin, user, install + */ + public $entity_type; + /** + * @var string + */ + public $business_name; + /** + * @var string + */ + public $first; + /** + * @var string + */ + public $last; + /** + * @var string + */ + public $email; + /** + * @var string + */ + public $phone; + /** + * @var string + */ + public $website; + /** + * @var string Tax or VAT ID. + */ + public $tax_id; + /** + * @var string + */ + public $address_street; + /** + * @var string + */ + public $address_apt; + /** + * @var string + */ + public $address_city; + /** + * @var string + */ + public $address_country; + /** + * @var string Two chars country code. + */ + public $address_country_code; + /** + * @var string + */ + public $address_state; + /** + * @var number Numeric ZIP code (cab be with leading zeros). + */ + public $address_zip; + + #endregion Properties + + + /** + * @param object|bool $event + */ + function __construct( $event = false ) { + parent::__construct( $event ); + } + + static function get_type() { + return 'billing'; + } }\ No newline at end of file
Vulnerability Existed: no No CWE Vulnerability Identified Old Code: Lines 1-95 with CRLF line endings (Windows style) Fixed Code: Lines 1-95 with LF line endings (Unix style) Explanation: This diff shows only a line ending normalization change (CRLF to LF conversion). The actual code content remains identical - no functional changes, logic modifications, or security fixes are present. The change is purely cosmetic, converting Windows-style line endings to Unix-style line endings. This is not a security vulnerability fix, nor does it introduce any security vulnerabilities. It's a code formatting/standardization change commonly made during development workflow normalization.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-entity.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-entity.php 2026-01-19 00:17:37.655045280 +0000@@ -1,159 +1,159 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Get object's public variables.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.0- *- * @param object $object- *- * @return array- */- function fs_get_object_public_vars( $object ) {- return get_object_vars( $object );- }-- class FS_Entity {- /**- * @var number- */- public $id;- /**- * @var string Datetime value in 'YYYY-MM-DD HH:MM:SS' format.- */- public $updated;- /**- * @var string Datetime value in 'YYYY-MM-DD HH:MM:SS' format.- */- public $created;-- /**- * @param bool|object $entity- */- function __construct( $entity = false ) {- if ( ! ( $entity instanceof stdClass ) && ! ( $entity instanceof FS_Entity ) ) {- return;- }-- $props = fs_get_object_public_vars( $this );-- foreach ( $props as $key => $def_value ) {- $this->{$key} = isset( $entity->{$key} ) ?- $entity->{$key} :- $def_value;- }- }-- static function get_type() {- return 'type';- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.6- *- * @param FS_Entity $entity1- * @param FS_Entity $entity2- *- * @return bool- */- static function equals( $entity1, $entity2 ) {- if ( is_null( $entity1 ) && is_null( $entity2 ) ) {- return true;- } else if ( is_object( $entity1 ) && is_object( $entity2 ) ) {- return ( $entity1->id == $entity2->id );- } else if ( is_object( $entity1 ) ) {- return is_null( $entity1->id );- } else {- return is_null( $entity2->id );- }- }-- private $_is_updated = false;-- /**- * Update object property.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @param string|array[string]mixed $key- * @param string|bool $val- *- * @return bool- */- function update( $key, $val = false ) {- if ( ! is_array( $key ) ) {- $key = array( $key => $val );- }-- $is_updated = false;-- foreach ( $key as $k => $v ) {- if ( $this->{$k} === $v ) {- continue;- }-- if ( ( is_string( $this->{$k} ) && is_numeric( $v ) ||- ( is_numeric( $this->{$k} ) && is_string( $v ) ) ) &&- $this->{$k} == $v- ) {- continue;- }-- // Update value.- $this->{$k} = $v;-- $is_updated = true;- }-- $this->_is_updated = $is_updated;-- return $is_updated;- }-- /**- * Checks if entity was updated.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- function is_updated() {- return $this->_is_updated;- }-- /**- * @param $id- *- * @author Vova Feldman (@svovaf)- * @since 1.1.2- *- * @return bool- */- static function is_valid_id($id){- return is_numeric($id);- }-- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.1- *- * @return string- */- public static function get_class_name() {- return get_called_class();- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Get object's public variables. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.0 + * + * @param object $object + * + * @return array + */ + function fs_get_object_public_vars( $object ) { + return get_object_vars( $object ); + } + + class FS_Entity { + /** + * @var number + */ + public $id; + /** + * @var string Datetime value in 'YYYY-MM-DD HH:MM:SS' format. + */ + public $updated; + /** + * @var string Datetime value in 'YYYY-MM-DD HH:MM:SS' format. + */ + public $created; + + /** + * @param bool|object $entity + */ + function __construct( $entity = false ) { + if ( ! ( $entity instanceof stdClass ) && ! ( $entity instanceof FS_Entity ) ) { + return; + } + + $props = fs_get_object_public_vars( $this ); + + foreach ( $props as $key => $def_value ) { + $this->{$key} = isset( $entity->{$key} ) ? + $entity->{$key} : + $def_value; + } + } + + static function get_type() { + return 'type'; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.6 + * + * @param FS_Entity $entity1 + * @param FS_Entity $entity2 + * + * @return bool + */ + static function equals( $entity1, $entity2 ) { + if ( is_null( $entity1 ) && is_null( $entity2 ) ) { + return true; + } else if ( is_object( $entity1 ) && is_object( $entity2 ) ) { + return ( $entity1->id == $entity2->id ); + } else if ( is_object( $entity1 ) ) { + return is_null( $entity1->id ); + } else { + return is_null( $entity2->id ); + } + } + + private $_is_updated = false; + + /** + * Update object property. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @param string|array[string]mixed $key + * @param string|bool $val + * + * @return bool + */ + function update( $key, $val = false ) { + if ( ! is_array( $key ) ) { + $key = array( $key => $val ); + } + + $is_updated = false; + + foreach ( $key as $k => $v ) { + if ( $this->{$k} === $v ) { + continue; + } + + if ( ( is_string( $this->{$k} ) && is_numeric( $v ) || + ( is_numeric( $this->{$k} ) && is_string( $v ) ) ) && + $this->{$k} == $v + ) { + continue; + } + + // Update value. + $this->{$k} = $v; + + $is_updated = true; + } + + $this->_is_updated = $is_updated; + + return $is_updated; + } + + /** + * Checks if entity was updated. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @return bool + */ + function is_updated() { + return $this->_is_updated; + } + + /** + * @param $id + * + * @author Vova Feldman (@svovaf) + * @since 1.1.2 + * + * @return bool + */ + static function is_valid_id($id){ + return is_numeric($id); + } + + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.1 + * + * @return string + */ + public static function get_class_name() { + return get_called_class(); + } }\ No newline at end of file
Vulnerability Existed: no No Vulnerabilities Detected - inc/freemius/includes/entities/class-fs-entity.php Explanation: This diff shows only whitespace and line ending changes (converting from Unix LF to Windows CRLF line endings). The actual code content remains identical between versions 1.2.11 and 1.2.12. No security fixes, no code modifications, and no vulnerabilities were introduced or remediated. This is a formatting-only change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-payment.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-payment.php 2026-01-19 00:17:37.655045280 +0000@@ -1,168 +1,168 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2016, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Payment extends FS_Entity {-- #region Properties-- /**- * @var number- */- public $plugin_id;- /**- * @var number- */- public $user_id;- /**- * @var number- */- public $install_id;- /**- * @var number- */- public $subscription_id;- /**- * @var number- */- public $plan_id;- /**- * @var number- */- public $license_id;- /**- * @var float- */- public $gross;- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.0- *- * @var string One of the following: `usd`, `gbp`, `eur`.- */- public $currency;- /**- * @var number- */- public $bound_payment_id;- /**- * @var string- */- public $external_id;- /**- * @var string- */- public $gateway;- /**- * @var string ISO 3166-1 alpha-2 - two-letter country code.- *- * @link http://www.wikiwand.com/en/ISO_3166-1_alpha-2- */- public $country_code;- /**- * @var string- */- public $vat_id;- /**- * @var float Actual Tax / VAT in $$$- */- public $vat;- /**- * @var int Payment source.- */- public $source = 0;-- #endregion Properties-- const CURRENCY_USD = 'usd';- const CURRENCY_GBP = 'gbp';- const CURRENCY_EUR = 'eur';-- /**- * @param object|bool $payment- */- function __construct( $payment = false ) {- parent::__construct( $payment );- }-- static function get_type() {- return 'payment';- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.0- *- * @return bool- */- function is_refund() {- return ( parent::is_valid_id( $this->bound_payment_id ) && 0 > $this->gross );- }-- /**- * Checks if the payment was migrated from another platform.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.2- *- * @return bool- */- function is_migrated() {- return ( 0 != $this->source );- }-- /**- * Returns the gross in this format:- * `{symbol}{amount | 2 decimal digits} {currency | uppercase}`- *- * Examples: £9.99 GBP, -£9.99 GBP.- *- * @author Leo Fajardo (@leorw)- * @since 2.3.0- *- * @return string- */- function formatted_gross()- {- return (- ( $this->gross < 0 ? '-' : '' ) .- $this->get_symbol() .- number_format( abs( $this->gross ), 2, '.', ',' ) . ' ' .- strtoupper( $this->currency )- );- }-- /**- * A map between supported currencies with their symbols.- *- * @var array<string,string>- */- static $CURRENCY_2_SYMBOL;-- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.0- *- * @return string- */- private function get_symbol() {- if ( ! isset( self::$CURRENCY_2_SYMBOL ) ) {- // Lazy load.- self::$CURRENCY_2_SYMBOL = array(- self::CURRENCY_USD => '$',- self::CURRENCY_GBP => '£',- self::CURRENCY_EUR => '€',- );- }-- return self::$CURRENCY_2_SYMBOL[ $this->currency ];- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2016, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Payment extends FS_Entity { + + #region Properties + + /** + * @var number + */ + public $plugin_id; + /** + * @var number + */ + public $user_id; + /** + * @var number + */ + public $install_id; + /** + * @var number + */ + public $subscription_id; + /** + * @var number + */ + public $plan_id; + /** + * @var number + */ + public $license_id; + /** + * @var float + */ + public $gross; + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.0 + * + * @var string One of the following: `usd`, `gbp`, `eur`. + */ + public $currency; + /** + * @var number + */ + public $bound_payment_id; + /** + * @var string + */ + public $external_id; + /** + * @var string + */ + public $gateway; + /** + * @var string ISO 3166-1 alpha-2 - two-letter country code. + * + * @link http://www.wikiwand.com/en/ISO_3166-1_alpha-2 + */ + public $country_code; + /** + * @var string + */ + public $vat_id; + /** + * @var float Actual Tax / VAT in $$$ + */ + public $vat; + /** + * @var int Payment source. + */ + public $source = 0; + + #endregion Properties + + const CURRENCY_USD = 'usd'; + const CURRENCY_GBP = 'gbp'; + const CURRENCY_EUR = 'eur'; + + /** + * @param object|bool $payment + */ + function __construct( $payment = false ) { + parent::__construct( $payment ); + } + + static function get_type() { + return 'payment'; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.0 + * + * @return bool + */ + function is_refund() { + return ( parent::is_valid_id( $this->bound_payment_id ) && 0 > $this->gross ); + } + + /** + * Checks if the payment was migrated from another platform. + * + * @author Vova Feldman (@svovaf) + * @since 2.0.2 + * + * @return bool + */ + function is_migrated() { + return ( 0 != $this->source ); + } + + /** + * Returns the gross in this format: + * `{symbol}{amount | 2 decimal digits} {currency | uppercase}` + * + * Examples: £9.99 GBP, -£9.99 GBP. + * + * @author Leo Fajardo (@leorw) + * @since 2.3.0 + * + * @return string + */ + function formatted_gross() + { + return ( + ( $this->gross < 0 ? '-' : '' ) . + $this->get_symbol() . + number_format( abs( $this->gross ), 2, '.', ',' ) . ' ' . + strtoupper( $this->currency ) + ); + } + + /** + * A map between supported currencies with their symbols. + * + * @var array<string,string> + */ + static $CURRENCY_2_SYMBOL; + + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.0 + * + * @return string + */ + private function get_symbol() { + if ( ! isset( self::$CURRENCY_2_SYMBOL ) ) { + // Lazy load. + self::$CURRENCY_2_SYMBOL = array( + self::CURRENCY_USD => '$', + self::CURRENCY_GBP => '£', + self::CURRENCY_EUR => '€', + ); + } + + return self::$CURRENCY_2_SYMBOL[ $this->currency ]; + } }\ No newline at end of file
Vulnerability Existed: no No Security Vulnerabilities Detected - Line Endings Change Only Explanation: The diff shows only a formatting change where the file's line endings were converted from CRLF (Windows-style, `\r\n`) to LF (Unix-style, `\n`). The actual code content remains identical between versions 1.2.11 and 1.2.12. No functional changes, logic modifications, or security-related code alterations were made. This is a purely cosmetic whitespace/line ending normalization with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-plugin-info.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-plugin-info.php 2026-01-19 00:17:37.655045280 +0000@@ -1,34 +1,34 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Plugin_Info extends FS_Entity {- public $plugin_id;- public $description;- public $short_description;- public $banner_url;- public $card_banner_url;- public $selling_point_0;- public $selling_point_1;- public $selling_point_2;- public $screenshots;-- /**- * @param stdClass|bool $plugin_info- */- function __construct( $plugin_info = false ) {- parent::__construct( $plugin_info );- }-- static function get_type() {- return 'plugin';- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Plugin_Info extends FS_Entity { + public $plugin_id; + public $description; + public $short_description; + public $banner_url; + public $card_banner_url; + public $selling_point_0; + public $selling_point_1; + public $selling_point_2; + public $screenshots; + + /** + * @param stdClass|bool $plugin_info + */ + function __construct( $plugin_info = false ) { + parent::__construct( $plugin_info ); + } + + static function get_type() { + return 'plugin'; + } }\ No newline at end of file
# Security Analysis Results **Vulnerability Existed:** no **No Security Vulnerabilities Detected** **Explanation:** The diff shows only line ending changes (CRLF to LF conversion) in the file `inc/freemius/includes/entities/class-fs-plugin-info.php`. The actual code content remains identical between versions 1.2.11 and 1.2.12. The changes are: - Line ending normalization from Windows-style (CRLF, `\r\n`) to Unix-style (LF, `\n`) - No functional code modifications - No new code introduction - No removal of security controls This is a formatting/whitespace change only and does not introduce, fix, or relate to any security vulnerabilities. The class definition, constructor, and method implementations are unchanged in terms of their security posture.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-plugin-license.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-plugin-license.php 2026-01-19 00:17:37.655045280 +0000@@ -1,334 +1,334 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.5- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Class FS_Plugin_License- */- class FS_Plugin_License extends FS_Entity {-- #region Properties-- /**- * @var number- */- public $plugin_id;- /**- * @var number- */- public $user_id;- /**- * @var number- */- public $plan_id;- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.0- *- * @var string- */- public $parent_plan_name;- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.0- *- * @var string- */- public $parent_plan_title;- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.0- *- * @var number- */- public $parent_license_id;- /**- * @author Leo Fajardo (@leorw)- * @since 2.4.0- *- * @var array- */- public $products;- /**- * @var number- */- public $pricing_id;- /**- * @var int|null- */- public $quota;- /**- * @var int- */- public $activated;- /**- * @var int- */- public $activated_local;- /**- * @var string- */- public $expiration;- /**- * @var string- */- public $secret_key;- /**- * @var bool- */- public $is_whitelabeled;- /**- * @var bool $is_free_localhost Defaults to true. If true, allow unlimited localhost installs with the same- * license.- */- public $is_free_localhost;- /**- * @var bool $is_block_features Defaults to true. If false, don't block features after license expiry - only- * block updates and support.- */- public $is_block_features;- /**- * @var bool- */- public $is_cancelled;-- #endregion Properties-- /**- * @param stdClass|bool $license- */- function __construct( $license = false ) {- parent::__construct( $license );- }-- /**- * Get entity type.- *- * @return string- */- static function get_type() {- return 'license';- }-- /**- * Check how many site activations left.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.5- *- * @return int- */- function left() {- if ( ! $this->is_features_enabled() ) {- return 0;- }-- if ( $this->is_unlimited() ) {- return 999;- }-- return ( $this->quota - $this->activated - ( $this->is_free_localhost ? 0 : $this->activated_local ) );- }-- /**- * Check if single site license.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.8.1- *- * @return bool- */- function is_single_site() {- return ( is_numeric( $this->quota ) && 1 == $this->quota );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.5- *- * @return bool- */- function is_expired() {- return ! $this->is_lifetime() && ( strtotime( $this->expiration ) < WP_FS__SCRIPT_START_TIME );- }-- /**- * Check if license is not expired.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1- *- * @return bool- */- function is_valid() {- return ! $this->is_expired();- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.6- *- * @return bool- */- function is_lifetime() {- return is_null( $this->expiration );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.2.0- *- * @return bool- */- function is_unlimited() {- return is_null( $this->quota );- }-- /**- * Check if license is fully utilized.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.6- *- * @param bool|null $is_localhost- *- * @return bool- */- function is_utilized( $is_localhost = null ) {- if ( is_null( $is_localhost ) ) {- $is_localhost = WP_FS__IS_LOCALHOST_FOR_SERVER;- }-- if ( $this->is_unlimited() ) {- return false;- }-- return ! ( $this->is_free_localhost && $is_localhost ) &&- ( $this->quota <= $this->activated + ( $this->is_free_localhost ? 0 : $this->activated_local ) );- }-- /**- * Check if license can be activated.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param bool|null $is_localhost- *- * @return bool- */- function can_activate( $is_localhost = null ) {- return ! $this->is_utilized( $is_localhost ) && $this->is_features_enabled();- }-- /**- * Check if license can be activated on a given number of production and localhost sites.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param int $production_count- * @param int $localhost_count- *- * @return bool- */- function can_activate_bulk( $production_count, $localhost_count ) {- if ( $this->is_unlimited() ) {- return true;- }-- /**- * For simplicity, the logic will work as following: when given X sites to activate the license on, if it's- * possible to activate on ALL of them, do the activation. If it's not possible to activate on ALL of them,- * do NOT activate on any of them.- */- return ( $this->quota >= $this->activated + $production_count + ( $this->is_free_localhost ? 0 : $this->activated_local + $localhost_count ) );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.2.1- *- * @return bool- */- function is_active() {- return ( ! $this->is_cancelled );- }-- /**- * Check if license's plan features are enabled.- *- * - Either if plan not expired- * - If expired, based on the configuration to block features or not.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.6- *- * @return bool- */- function is_features_enabled() {- return $this->is_active() && ( ! $this->is_block_features || ! $this->is_expired() );- }-- /**- * Subscription considered to be new without any payments- * if the license expires in less than 24 hours- * from the license creation.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- function is_first_payment_pending() {- if ( $this->is_lifetime() ) {- return false;- }-- return ( WP_FS__TIME_24_HOURS_IN_SEC >= strtotime( $this->expiration ) - strtotime( $this->created ) );- }-- /**- * @return int- */- function total_activations() {- return ( $this->activated + $this->activated_local );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 2.3.1- *- * @return string- */- function get_html_escaped_masked_secret_key() {- return self::mask_secret_key_for_html( $this->secret_key );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 2.3.1- *- * @param string $secret_key- *- * @return string- */- static function mask_secret_key_for_html( $secret_key ) {- return (- // Initial 6 chars - sk_ABC- htmlspecialchars( substr( $secret_key, 0, 6 ) ) .- // Masking- str_pad( '', ( strlen( $secret_key ) - 9 ) * 6, '•' ) .- // Last 3 chars.- htmlspecialchars( substr( $secret_key, - 3 ) )- );- }- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.5 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Class FS_Plugin_License + */ + class FS_Plugin_License extends FS_Entity { + + #region Properties + + /** + * @var number + */ + public $plugin_id; + /** + * @var number + */ + public $user_id; + /** + * @var number + */ + public $plan_id; + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.0 + * + * @var string + */ + public $parent_plan_name; + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.0 + * + * @var string + */ + public $parent_plan_title; + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.0 + * + * @var number + */ + public $parent_license_id; + /** + * @author Leo Fajardo (@leorw) + * @since 2.4.0 + * + * @var array + */ + public $products; + /** + * @var number + */ + public $pricing_id; + /** + * @var int|null + */ + public $quota; + /** + * @var int + */ + public $activated; + /** + * @var int + */ + public $activated_local; + /** + * @var string + */ + public $expiration; + /** + * @var string + */ + public $secret_key; + /** + * @var bool + */ + public $is_whitelabeled; + /** + * @var bool $is_free_localhost Defaults to true. If true, allow unlimited localhost installs with the same + * license. + */ + public $is_free_localhost; + /** + * @var bool $is_block_features Defaults to true. If false, don't block features after license expiry - only + * block updates and support. + */ + public $is_block_features; + /** + * @var bool + */ + public $is_cancelled; + + #endregion Properties + + /** + * @param stdClass|bool $license + */ + function __construct( $license = false ) { + parent::__construct( $license ); + } + + /** + * Get entity type. + * + * @return string + */ + static function get_type() { + return 'license'; + } + + /** + * Check how many site activations left. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.5 + * + * @return int + */ + function left() { + if ( ! $this->is_features_enabled() ) { + return 0; + } + + if ( $this->is_unlimited() ) { + return 999; + } + + return ( $this->quota - $this->activated - ( $this->is_free_localhost ? 0 : $this->activated_local ) ); + } + + /** + * Check if single site license. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.8.1 + * + * @return bool + */ + function is_single_site() { + return ( is_numeric( $this->quota ) && 1 == $this->quota ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.5 + * + * @return bool + */ + function is_expired() { + return ! $this->is_lifetime() && ( strtotime( $this->expiration ) < WP_FS__SCRIPT_START_TIME ); + } + + /** + * Check if license is not expired. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.1 + * + * @return bool + */ + function is_valid() { + return ! $this->is_expired(); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.6 + * + * @return bool + */ + function is_lifetime() { + return is_null( $this->expiration ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.2.0 + * + * @return bool + */ + function is_unlimited() { + return is_null( $this->quota ); + } + + /** + * Check if license is fully utilized. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.6 + * + * @param bool|null $is_localhost + * + * @return bool + */ + function is_utilized( $is_localhost = null ) { + if ( is_null( $is_localhost ) ) { + $is_localhost = WP_FS__IS_LOCALHOST_FOR_SERVER; + } + + if ( $this->is_unlimited() ) { + return false; + } + + return ! ( $this->is_free_localhost && $is_localhost ) && + ( $this->quota <= $this->activated + ( $this->is_free_localhost ? 0 : $this->activated_local ) ); + } + + /** + * Check if license can be activated. + * + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + * + * @param bool|null $is_localhost + * + * @return bool + */ + function can_activate( $is_localhost = null ) { + return ! $this->is_utilized( $is_localhost ) && $this->is_features_enabled(); + } + + /** + * Check if license can be activated on a given number of production and localhost sites. + * + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + * + * @param int $production_count + * @param int $localhost_count + * + * @return bool + */ + function can_activate_bulk( $production_count, $localhost_count ) { + if ( $this->is_unlimited() ) { + return true; + } + + /** + * For simplicity, the logic will work as following: when given X sites to activate the license on, if it's + * possible to activate on ALL of them, do the activation. If it's not possible to activate on ALL of them, + * do NOT activate on any of them. + */ + return ( $this->quota >= $this->activated + $production_count + ( $this->is_free_localhost ? 0 : $this->activated_local + $localhost_count ) ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.2.1 + * + * @return bool + */ + function is_active() { + return ( ! $this->is_cancelled ); + } + + /** + * Check if license's plan features are enabled. + * + * - Either if plan not expired + * - If expired, based on the configuration to block features or not. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.6 + * + * @return bool + */ + function is_features_enabled() { + return $this->is_active() && ( ! $this->is_block_features || ! $this->is_expired() ); + } + + /** + * Subscription considered to be new without any payments + * if the license expires in less than 24 hours + * from the license creation. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @return bool + */ + function is_first_payment_pending() { + if ( $this->is_lifetime() ) { + return false; + } + + return ( WP_FS__TIME_24_HOURS_IN_SEC >= strtotime( $this->expiration ) - strtotime( $this->created ) ); + } + + /** + * @return int + */ + function total_activations() { + return ( $this->activated + $this->activated_local ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 2.3.1 + * + * @return string + */ + function get_html_escaped_masked_secret_key() { + return self::mask_secret_key_for_html( $this->secret_key ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 2.3.1 + * + * @param string $secret_key + * + * @return string + */ + static function mask_secret_key_for_html( $secret_key ) { + return ( + // Initial 6 chars - sk_ABC + htmlspecialchars( substr( $secret_key, 0, 6 ) ) . + // Masking + str_pad( '', ( strlen( $secret_key ) - 9 ) * 6, '•' ) . + // Last 3 chars. + htmlspecialchars( substr( $secret_key, - 3 ) ) + ); + } + }
Vulnerability Existed: no Analysis Complete The provided diff shows only a line ending change (CRLF to LF conversion) across the entire file. There are no code logic changes, no functional modifications, and no security-related alterations. The file content remains identical in terms of functionality and security posture. The `mask_secret_key_for_html()` method at the end of the file continues to properly use `htmlspecialchars()` for escaping the visible portions of the secret key, which is the appropriate security control for this operation. No vulnerabilities were introduced or fixed in this diff.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-plugin-plan.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-plugin-plan.php 2026-01-19 00:17:37.655045280 +0000@@ -1,149 +1,149 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.5- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Class FS_Plugin_Plan- *- * @property FS_Pricing[] $pricing- */- class FS_Plugin_Plan extends FS_Entity {-- #region Properties-- /**- * @var number- */- public $plugin_id;- /**- * @var string- */- public $name;- /**- * @var string- */- public $title;- /**- * @var string- */- public $description;- /**- * @var bool Defaults to true. If true, allow unlimited localhost installs with the same license.- */- public $is_free_localhost;- /**- * @var bool Defaults to true. If false, don't block features after license expiry - only block updates and- * support.- */- public $is_block_features;- /**- * @var int- */- public $license_type;- /**- * @var bool- */- public $is_https_support;- /**- * @var int Trial days.- */- public $trial_period;- /**- * @var string If true, require payment for trial.- */- public $is_require_subscription;- /**- * @var string Knowledge Base URL.- */- public $support_kb;- /**- * @var string Support Forum URL.- */- public $support_forum;- /**- * @var string Support email address.- */- public $support_email;- /**- * @var string Support phone.- */- public $support_phone;- /**- * @var string Support skype username.- */- public $support_skype;- /**- * @var bool Is personal success manager supported with the plan.- */- public $is_success_manager;- /**- * @var bool Is featured plan.- */- public $is_featured;- /**- * @var bool Is hidden plan.- */- public $is_hidden;-- #endregion Properties-- /**- * @param object|bool $plan- */- function __construct( $plan = false ) {- parent::__construct( $plan );-- if ( is_object( $plan ) ) {- $this->name = strtolower( $plan->name );- }- }-- static function get_type() {- return 'plan';- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- function is_free() {- return ( 'free' === $this->name );- }-- /**- * Checks if this plan supports "Technical Support".- *- * @author Leo Fajardo (leorw)- * @since 1.2.0- *- * @return bool- */- function has_technical_support() {- return ( ! empty( $this->support_email ) ||- ! empty( $this->support_skype ) ||- ! empty( $this->support_phone ) ||- ! empty( $this->is_success_manager )- );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- function has_trial() {- return ! $this->is_free() &&- is_numeric( $this->trial_period ) && ( $this->trial_period > 0 );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.5 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Class FS_Plugin_Plan + * + * @property FS_Pricing[] $pricing + */ + class FS_Plugin_Plan extends FS_Entity { + + #region Properties + + /** + * @var number + */ + public $plugin_id; + /** + * @var string + */ + public $name; + /** + * @var string + */ + public $title; + /** + * @var string + */ + public $description; + /** + * @var bool Defaults to true. If true, allow unlimited localhost installs with the same license. + */ + public $is_free_localhost; + /** + * @var bool Defaults to true. If false, don't block features after license expiry - only block updates and + * support. + */ + public $is_block_features; + /** + * @var int + */ + public $license_type; + /** + * @var bool + */ + public $is_https_support; + /** + * @var int Trial days. + */ + public $trial_period; + /** + * @var string If true, require payment for trial. + */ + public $is_require_subscription; + /** + * @var string Knowledge Base URL. + */ + public $support_kb; + /** + * @var string Support Forum URL. + */ + public $support_forum; + /** + * @var string Support email address. + */ + public $support_email; + /** + * @var string Support phone. + */ + public $support_phone; + /** + * @var string Support skype username. + */ + public $support_skype; + /** + * @var bool Is personal success manager supported with the plan. + */ + public $is_success_manager; + /** + * @var bool Is featured plan. + */ + public $is_featured; + /** + * @var bool Is hidden plan. + */ + public $is_hidden; + + #endregion Properties + + /** + * @param object|bool $plan + */ + function __construct( $plan = false ) { + parent::__construct( $plan ); + + if ( is_object( $plan ) ) { + $this->name = strtolower( $plan->name ); + } + } + + static function get_type() { + return 'plan'; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @return bool + */ + function is_free() { + return ( 'free' === $this->name ); + } + + /** + * Checks if this plan supports "Technical Support". + * + * @author Leo Fajardo (leorw) + * @since 1.2.0 + * + * @return bool + */ + function has_technical_support() { + return ( ! empty( $this->support_email ) || + ! empty( $this->support_skype ) || + ! empty( $this->support_phone ) || + ! empty( $this->is_success_manager ) + ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @return bool + */ + function has_trial() { + return ! $this->is_free() && + is_numeric( $this->trial_period ) && ( $this->trial_period > 0 ); + } }\ No newline at end of file
Vulnerability Existed: no No CWE - No vulnerabilities detected - inc/freemius/includes/entities/class-fs-plugin-plan.php (entire file) Old Code: Lines 1-149 with CRLF line endings Fixed Code: Lines 1-149 with LF line endings Explanation: The diff shows only line ending changes (CRLF to LF conversion). The actual code logic, structure, and security mechanisms remain identical. No security vulnerabilities were introduced or fixed. This is a formatting/normalization change commonly applied during development workflows to ensure consistent line endings across the codebase. No security-relevant code modifications are present in this diff.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-plugin-tag.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-plugin-tag.php 2026-01-19 00:17:37.655045280 +0000@@ -1,64 +1,64 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2018, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.0.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Plugin_Tag extends FS_Entity {- /**- * @var string- */- public $version;- /**- * @var string- */- public $url;- /**- * @var string- */- public $requires_platform_version;- /**- * @var string- */- public $requires_programming_language_version;- /**- * @var string- */- public $tested_up_to_version;- /**- * @var bool- */- public $has_free;- /**- * @var bool- */- public $has_premium;- /**- * @var string One of the following: `pending`, `beta`, `unreleased`.- */- public $release_mode;-- function __construct( $tag = false ) {- parent::__construct( $tag );- }-- static function get_type() {- return 'tag';- }-- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.0- *- * @return bool- */- function is_beta() {- return ( 'beta' === $this->release_mode );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2018, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.0.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Plugin_Tag extends FS_Entity { + /** + * @var string + */ + public $version; + /** + * @var string + */ + public $url; + /** + * @var string + */ + public $requires_platform_version; + /** + * @var string + */ + public $requires_programming_language_version; + /** + * @var string + */ + public $tested_up_to_version; + /** + * @var bool + */ + public $has_free; + /** + * @var bool + */ + public $has_premium; + /** + * @var string One of the following: `pending`, `beta`, `unreleased`. + */ + public $release_mode; + + function __construct( $tag = false ) { + parent::__construct( $tag ); + } + + static function get_type() { + return 'tag'; + } + + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.0 + * + * @return bool + */ + function is_beta() { + return ( 'beta' === $this->release_mode ); + } }\ No newline at end of file
Vulnerability Existed: no Explanation: This diff contains only whitespace/line ending changes (converting from Unix LF to Windows CRLF line endings or similar formatting normalization). The actual code logic, structure, and security posture remain completely unchanged. No vulnerabilities were introduced or fixed - this is purely a formatting/encoding update to the file. All PHP code, class definitions, methods, and logic are identical between the old and new versions.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-plugin.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-plugin.php 2026-01-19 00:17:37.655045280 +0000@@ -1,164 +1,164 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Plugin extends FS_Scope_Entity {- /**- * @since 1.0.6- * @var null|number- */- public $parent_plugin_id;- /**- * @var string- */- public $title;- /**- * @var string- */- public $slug;- /**- * @author Leo Fajardo (@leorw)- * @since 2.2.1- *- * @var string- */- public $premium_slug;- /**- * @since 1.2.2- *- * @var string 'plugin' or 'theme'- */- public $type;- /**- * @author Leo Fajardo (@leorw)- *- * @since 1.2.3- *- * @var string|false false if the module doesn't have an affiliate program or one of the following: 'selected', 'customers', or 'all'.- */- public $affiliate_moderation;- /**- * @var bool Set to true if the free version of the module is hosted on WordPress.org. Defaults to true.- */- public $is_wp_org_compliant = true;- /**- * @author Leo Fajardo (@leorw)- * @since 2.2.5- *- * @var int- */- public $premium_releases_count;-- #region Install Specific Properties-- /**- * @var string- */- public $file;- /**- * @var string- */- public $version;- /**- * @var bool- */- public $auto_update;- /**- * @var FS_Plugin_Info- */- public $info;- /**- * @since 1.0.9- *- * @var bool- */- public $is_premium;- /**- * @author Leo Fajardo (@leorw)- * @since 2.2.1- *- * @var string- */- public $premium_suffix;- /**- * @since 1.0.9- *- * @var bool- */- public $is_live;- /**- * @since 2.2.3- * @var null|number- */- public $bundle_id;- /**- * @since 2.3.1- * @var null|string- */- public $bundle_public_key;- /**- * @since 2.5.4- * @var null|array- */- public $opt_in_moderation;-- const AFFILIATE_MODERATION_CUSTOMERS = 'customers';-- #endregion Install Specific Properties-- /**- * @param stdClass|bool $plugin- */- function __construct( $plugin = false ) {- parent::__construct( $plugin );-- $this->is_premium = false;- $this->is_live = true;-- if ( empty( $this->premium_slug ) && ! empty( $plugin->slug ) ) {- $this->premium_slug = "{$this->slug}-premium";- }-- if ( empty( $this->premium_suffix ) ) {- $this->premium_suffix = '(Premium)';- }-- if ( isset( $plugin->info ) && is_object( $plugin->info ) ) {- $this->info = new FS_Plugin_Info( $plugin->info );- }- }-- /**- * Check if plugin is an add-on (has parent).- *- * @author Vova Feldman (@svovaf)- * @since 1.0.6- *- * @return bool- */- function is_addon() {- return isset( $this->parent_plugin_id ) && is_numeric( $this->parent_plugin_id );- }-- /**- * @author Leo Fajardo (@leorw)- * @since 1.2.3- *- * @return bool- */- function has_affiliate_program() {- return ( ! empty( $this->affiliate_moderation ) );- }-- static function get_type() {- return 'plugin';- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Plugin extends FS_Scope_Entity { + /** + * @since 1.0.6 + * @var null|number + */ + public $parent_plugin_id; + /** + * @var string + */ + public $title; + /** + * @var string + */ + public $slug; + /** + * @author Leo Fajardo (@leorw) + * @since 2.2.1 + * + * @var string + */ + public $premium_slug; + /** + * @since 1.2.2 + * + * @var string 'plugin' or 'theme' + */ + public $type; + /** + * @author Leo Fajardo (@leorw) + * + * @since 1.2.3 + * + * @var string|false false if the module doesn't have an affiliate program or one of the following: 'selected', 'customers', or 'all'. + */ + public $affiliate_moderation; + /** + * @var bool Set to true if the free version of the module is hosted on WordPress.org. Defaults to true. + */ + public $is_wp_org_compliant = true; + /** + * @author Leo Fajardo (@leorw) + * @since 2.2.5 + * + * @var int + */ + public $premium_releases_count; + + #region Install Specific Properties + + /** + * @var string + */ + public $file; + /** + * @var string + */ + public $version; + /** + * @var bool + */ + public $auto_update; + /** + * @var FS_Plugin_Info + */ + public $info; + /** + * @since 1.0.9 + * + * @var bool + */ + public $is_premium; + /** + * @author Leo Fajardo (@leorw) + * @since 2.2.1 + * + * @var string + */ + public $premium_suffix; + /** + * @since 1.0.9 + * + * @var bool + */ + public $is_live; + /** + * @since 2.2.3 + * @var null|number + */ + public $bundle_id; + /** + * @since 2.3.1 + * @var null|string + */ + public $bundle_public_key; + /** + * @since 2.5.4 + * @var null|array + */ + public $opt_in_moderation; + + const AFFILIATE_MODERATION_CUSTOMERS = 'customers'; + + #endregion Install Specific Properties + + /** + * @param stdClass|bool $plugin + */ + function __construct( $plugin = false ) { + parent::__construct( $plugin ); + + $this->is_premium = false; + $this->is_live = true; + + if ( empty( $this->premium_slug ) && ! empty( $plugin->slug ) ) { + $this->premium_slug = "{$this->slug}-premium"; + } + + if ( empty( $this->premium_suffix ) ) { + $this->premium_suffix = '(Premium)'; + } + + if ( isset( $plugin->info ) && is_object( $plugin->info ) ) { + $this->info = new FS_Plugin_Info( $plugin->info ); + } + } + + /** + * Check if plugin is an add-on (has parent). + * + * @author Vova Feldman (@svovaf) + * @since 1.0.6 + * + * @return bool + */ + function is_addon() { + return isset( $this->parent_plugin_id ) && is_numeric( $this->parent_plugin_id ); + } + + /** + * @author Leo Fajardo (@leorw) + * @since 1.2.3 + * + * @return bool + */ + function has_affiliate_program() { + return ( ! empty( $this->affiliate_moderation ) ); + } + + static function get_type() { + return 'plugin'; + } }\ No newline at end of file
Vulnerability Existed: no Explanation: This diff shows only line ending changes (CRLF to LF conversion) across the entire file. The actual code content remains completely identical - there are no functional changes, logic modifications, or code alterations that would introduce or fix security vulnerabilities. This is purely a formatting/whitespace normalization that has no security implications. The PHP code structure, function implementations, and class definitions are unchanged between versions 1.2.11 and 1.2.12.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-pricing.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-pricing.php 2026-01-19 00:17:37.655045280 +0000@@ -1,157 +1,157 @@-<?php- /**- * @package Freemius for EDD Add-On- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Pricing extends FS_Entity {-- #region Properties-- /**- * @var number- */- public $plan_id;- /**- * @var int- */- public $licenses;- /**- * @var null|float- */- public $monthly_price;- /**- * @var null|float- */- public $annual_price;- /**- * @var null|float- */- public $lifetime_price;- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.1- *- * @var string One of the following: `usd`, `gbp`, `eur`.- */- public $currency;-- #endregion Properties-- /**- * @param object|bool $pricing- */- function __construct( $pricing = false ) {- parent::__construct( $pricing );- }-- static function get_type() {- return 'pricing';- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.8- *- * @return bool- */- function has_monthly() {- return ( is_numeric( $this->monthly_price ) && $this->monthly_price > 0 );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.8- *- * @return bool- */- function has_annual() {- return ( is_numeric( $this->annual_price ) && $this->annual_price > 0 );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.8- *- * @return bool- */- function has_lifetime() {- return ( is_numeric( $this->lifetime_price ) && $this->lifetime_price > 0 );- }-- /**- * Check if unlimited licenses pricing.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.8- *- * @return bool- */- function is_unlimited() {- return is_null( $this->licenses );- }--- /**- * Check if pricing has more than one billing cycle.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.8- *- * @return bool- */- function is_multi_cycle() {- $cycles = 0;- if ( $this->has_monthly() ) {- $cycles ++;- }- if ( $this->has_annual() ) {- $cycles ++;- }- if ( $this->has_lifetime() ) {- $cycles ++;- }-- return $cycles > 1;- }-- /**- * Get annual over monthly discount.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.8- *- * @return int- */- function annual_discount_percentage() {- return floor( $this->annual_savings() / ( $this->monthly_price * 12 * ( $this->is_unlimited() ? 1 : $this->licenses ) ) * 100 );- }-- /**- * Get annual over monthly savings.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.8- *- * @return float- */- function annual_savings() {- return ( $this->monthly_price * 12 - $this->annual_price ) * ( $this->is_unlimited() ? 1 : $this->licenses );- }-- /**- * @author Leo Fajardo (@leorw)- * @since 2.3.1- *- * @return bool- */- function is_usd() {- return ( 'usd' === $this->currency );- }+<?php + /** + * @package Freemius for EDD Add-On + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Pricing extends FS_Entity { + + #region Properties + + /** + * @var number + */ + public $plan_id; + /** + * @var int + */ + public $licenses; + /** + * @var null|float + */ + public $monthly_price; + /** + * @var null|float + */ + public $annual_price; + /** + * @var null|float + */ + public $lifetime_price; + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.1 + * + * @var string One of the following: `usd`, `gbp`, `eur`. + */ + public $currency; + + #endregion Properties + + /** + * @param object|bool $pricing + */ + function __construct( $pricing = false ) { + parent::__construct( $pricing ); + } + + static function get_type() { + return 'pricing'; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.8 + * + * @return bool + */ + function has_monthly() { + return ( is_numeric( $this->monthly_price ) && $this->monthly_price > 0 ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.8 + * + * @return bool + */ + function has_annual() { + return ( is_numeric( $this->annual_price ) && $this->annual_price > 0 ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.8 + * + * @return bool + */ + function has_lifetime() { + return ( is_numeric( $this->lifetime_price ) && $this->lifetime_price > 0 ); + } + + /** + * Check if unlimited licenses pricing. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.8 + * + * @return bool + */ + function is_unlimited() { + return is_null( $this->licenses ); + } + + + /** + * Check if pricing has more than one billing cycle. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.8 + * + * @return bool + */ + function is_multi_cycle() { + $cycles = 0; + if ( $this->has_monthly() ) { + $cycles ++; + } + if ( $this->has_annual() ) { + $cycles ++; + } + if ( $this->has_lifetime() ) { + $cycles ++; + } + + return $cycles > 1; + } + + /** + * Get annual over monthly discount. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.8 + * + * @return int + */ + function annual_discount_percentage() { + return floor( $this->annual_savings() / ( $this->monthly_price * 12 * ( $this->is_unlimited() ? 1 : $this->licenses ) ) * 100 ); + } + + /** + * Get annual over monthly savings. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.8 + * + * @return float + */ + function annual_savings() { + return ( $this->monthly_price * 12 - $this->annual_price ) * ( $this->is_unlimited() ? 1 : $this->licenses ); + } + + /** + * @author Leo Fajardo (@leorw) + * @since 2.3.1 + * + * @return bool + */ + function is_usd() { + return ( 'usd' === $this->currency ); + } }\ No newline at end of file
Based on my analysis of the provided diff, here is my security assessment: --- **Vulnerability Existed: no** This diff contains only formatting/whitespace changes (line ending conversions from Windows CRLF to Unix LF format). The actual code logic, structure, and functionality remain completely identical between the two versions. **No security vulnerabilities are present in this diff** because: - No code logic was modified - No new functionality was added - No existing security controls were removed or weakened - The class structure and all methods remain functionally equivalent - All input validation and type checking logic is preserved This appears to be a routine code formatting or version control normalization update with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-scope-entity.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-scope-entity.php 2026-01-19 00:17:37.655045280 +0000@@ -1,29 +1,29 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.4- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Scope_Entity extends FS_Entity {- /**- * @var string- */- public $public_key;- /**- * @var string- */- public $secret_key;-- /**- * @param bool|stdClass $scope_entity- */- function __construct( $scope_entity = false ) {- parent::__construct( $scope_entity );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.4 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Scope_Entity extends FS_Entity { + /** + * @var string + */ + public $public_key; + /** + * @var string + */ + public $secret_key; + + /** + * @param bool|stdClass $scope_entity + */ + function __construct( $scope_entity = false ) { + parent::__construct( $scope_entity ); + } }\ No newline at end of file
# Security Analysis Report **File:** inc/freemius/includes/entities/class-fs-scope-entity.php --- ## Analysis Result **Vulnerability Existed:** no **No Security Vulnerabilities Detected** **Explanation:** The diff provided shows only line ending changes (LF to CRLF conversion or vice versa) and no actual code modifications. The file content remains identical: - Old Code: Unix line endings (LF - `\n`) - Fixed Code: Windows line endings (CRLF - `\r\n`) This is a formatting/normalization change with no security implications. The actual code logic, function signatures, class structure, and security-relevant implementations remain unchanged. There are no new security fixes or vulnerabilities introduced by this diff. The code itself does not introduce new vulnerabilities. The class properly: - Checks for WordPress `ABSPATH` constant definition - Uses proper object-oriented design with inheritance - Declares properties with appropriate visibility --- **Summary:** This is a line ending normalization commit with zero security impact.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-site.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-site.php 2026-01-19 00:17:37.655045280 +0000@@ -1,258 +1,258 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @property int $blog_id- */- #[AllowDynamicProperties]- class FS_Site extends FS_Scope_Entity {- /**- * @var number- */- public $site_id;- /**- * @var number- */- public $plugin_id;- /**- * @var number- */- public $user_id;- /**- * @var string- */- public $title;- /**- * @var string- */- public $url;- /**- * @var string- */- public $version;- /**- * @var string E.g. en-GB- */- public $language;- /**- * @var string Platform version (e.g WordPress version).- */- public $platform_version;- /**- * Freemius SDK version- *- * @author Leo Fajardo (@leorw)- * @since 1.2.2- *- * @var string SDK version (e.g.: 1.2.2)- */- public $sdk_version;- /**- * @var string Programming language version (e.g PHP version).- */- public $programming_language_version;- /**- * @var number|null- */- public $plan_id;- /**- * @var number|null- */- public $license_id;- /**- * @var number|null- */- public $trial_plan_id;- /**- * @var string|null- */- public $trial_ends;- /**- * @since 1.0.9- *- * @var bool- */- public $is_premium = false;- /**- * @author Leo Fajardo (@leorw)- *- * @since 1.2.1.5- * @deprecated Since 2.5.1- * @todo Remove after a few releases.- *- * @var bool- */- public $is_disconnected = false;- /**- * @since 2.0.0- *- * @var bool- */- public $is_active = true;- /**- * @since 2.0.0- *- * @var bool- */- public $is_uninstalled = false;- /**- * @author Edgar Melkonyan- *- * @since 2.4.2- *- * @var bool- */- public $is_beta;-- /**- * @param stdClass|bool $site- */- function __construct( $site = false ) {- parent::__construct( $site );-- if ( is_object( $site ) ) {- $this->plan_id = $site->plan_id;- }-- if ( ! is_bool( $this->is_disconnected ) ) {- $this->is_disconnected = false;- }- }-- static function get_type() {- return 'install';- }-- /**- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param string $url- *- * @return bool- */- static function is_localhost_by_address( $url ) {- if ( false !== strpos( $url, '127.0.0.1' ) ||- false !== strpos( $url, 'localhost' )- ) {- return true;- }-- if ( ! fs_starts_with( $url, 'http' ) ) {- $url = 'http://' . $url;- }-- $url_parts = parse_url( $url );-- $subdomain = $url_parts['host'];-- return (- // Starts with.- fs_starts_with( $subdomain, 'local.' ) ||- fs_starts_with( $subdomain, 'dev.' ) ||- fs_starts_with( $subdomain, 'test.' ) ||- fs_starts_with( $subdomain, 'stage.' ) ||- fs_starts_with( $subdomain, 'staging.' ) ||-- // Ends with.- fs_ends_with( $subdomain, '.dev' ) ||- fs_ends_with( $subdomain, '.test' ) ||- fs_ends_with( $subdomain, '.staging' ) ||- fs_ends_with( $subdomain, '.local' ) ||- fs_ends_with( $subdomain, '.example' ) ||- fs_ends_with( $subdomain, '.invalid' ) ||- // GoDaddy test/dev.- fs_ends_with( $subdomain, '.myftpupload.com' ) ||- // ngrok tunneling.- fs_ends_with( $subdomain, '.ngrok.io' ) ||- // wpsandbox.- fs_ends_with( $subdomain, '.wpsandbox.pro' ) ||- // SiteGround staging.- fs_starts_with( $subdomain, 'staging' ) ||- // WPEngine staging.- fs_ends_with( $subdomain, '.staging.wpengine.com' ) ||- fs_ends_with( $subdomain, '.dev.wpengine.com' ) ||- fs_ends_with( $subdomain, '.wpengine.com' ) ||- // Pantheon- ( fs_ends_with( $subdomain, 'pantheonsite.io' ) &&- ( fs_starts_with( $subdomain, 'test-' ) || fs_starts_with( $subdomain, 'dev-' ) ) ) ||- // Cloudways- fs_ends_with( $subdomain, '.cloudwaysapps.com' ) ||- // Kinsta- (- ( fs_starts_with( $subdomain, 'staging-' ) || fs_starts_with( $subdomain, 'env-' ) ) &&- ( fs_ends_with( $subdomain, '.kinsta.com' ) || fs_ends_with( $subdomain, '.kinsta.cloud' ) )- ) ||- // DesktopServer- fs_ends_with( $subdomain, '.dev.cc' ) ||- // Pressable- fs_ends_with( $subdomain, '.mystagingwebsite.com' ) ||- // WPMU DEV- ( fs_ends_with( $subdomain, '.tempurl.host' ) || fs_ends_with( $subdomain, '.wpmudev.host' ) ) ||- // Vendasta- ( fs_ends_with( $subdomain, '.websitepro-staging.com' ) || fs_ends_with( $subdomain, '.websitepro.hosting' ) ) ||- // InstaWP- fs_ends_with( $subdomain, '.instawp.xyz' )- );- }-- function is_localhost() {- return ( WP_FS__IS_LOCALHOST_FOR_SERVER || self::is_localhost_by_address( $this->url ) );- }-- /**- * Check if site in trial.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- function is_trial() {- return is_numeric( $this->trial_plan_id ) && ( strtotime( $this->trial_ends ) > WP_FS__SCRIPT_START_TIME );- }-- /**- * Check if user already utilized the trial with the current install.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- function is_trial_utilized() {- return is_numeric( $this->trial_plan_id );- }-- /**- * @author Edgar Melkonyan- *- * @return bool- */- function is_beta() {- return ( isset( $this->is_beta ) && true === $this->is_beta );- }-- /**- * @author Leo Fajardo (@leorw)- * @since 2.5.1- *- * @param string $site_url- *- * @return bool- */- function is_clone( $site_url ) {- $clone_install_url = trailingslashit( fs_strip_url_protocol( $this->url ) );-- return ( $clone_install_url !== $site_url );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @property int $blog_id + */ + #[AllowDynamicProperties] + class FS_Site extends FS_Scope_Entity { + /** + * @var number + */ + public $site_id; + /** + * @var number + */ + public $plugin_id; + /** + * @var number + */ + public $user_id; + /** + * @var string + */ + public $title; + /** + * @var string + */ + public $url; + /** + * @var string + */ + public $version; + /** + * @var string E.g. en-GB + */ + public $language; + /** + * @var string Platform version (e.g WordPress version). + */ + public $platform_version; + /** + * Freemius SDK version + * + * @author Leo Fajardo (@leorw) + * @since 1.2.2 + * + * @var string SDK version (e.g.: 1.2.2) + */ + public $sdk_version; + /** + * @var string Programming language version (e.g PHP version). + */ + public $programming_language_version; + /** + * @var number|null + */ + public $plan_id; + /** + * @var number|null + */ + public $license_id; + /** + * @var number|null + */ + public $trial_plan_id; + /** + * @var string|null + */ + public $trial_ends; + /** + * @since 1.0.9 + * + * @var bool + */ + public $is_premium = false; + /** + * @author Leo Fajardo (@leorw) + * + * @since 1.2.1.5 + * @deprecated Since 2.5.1 + * @todo Remove after a few releases. + * + * @var bool + */ + public $is_disconnected = false; + /** + * @since 2.0.0 + * + * @var bool + */ + public $is_active = true; + /** + * @since 2.0.0 + * + * @var bool + */ + public $is_uninstalled = false; + /** + * @author Edgar Melkonyan + * + * @since 2.4.2 + * + * @var bool + */ + public $is_beta; + + /** + * @param stdClass|bool $site + */ + function __construct( $site = false ) { + parent::__construct( $site ); + + if ( is_object( $site ) ) { + $this->plan_id = $site->plan_id; + } + + if ( ! is_bool( $this->is_disconnected ) ) { + $this->is_disconnected = false; + } + } + + static function get_type() { + return 'install'; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + * + * @param string $url + * + * @return bool + */ + static function is_localhost_by_address( $url ) { + if ( false !== strpos( $url, '127.0.0.1' ) || + false !== strpos( $url, 'localhost' ) + ) { + return true; + } + + if ( ! fs_starts_with( $url, 'http' ) ) { + $url = 'http://' . $url; + } + + $url_parts = parse_url( $url ); + + $subdomain = $url_parts['host']; + + return ( + // Starts with. + fs_starts_with( $subdomain, 'local.' ) || + fs_starts_with( $subdomain, 'dev.' ) || + fs_starts_with( $subdomain, 'test.' ) || + fs_starts_with( $subdomain, 'stage.' ) || + fs_starts_with( $subdomain, 'staging.' ) || + + // Ends with. + fs_ends_with( $subdomain, '.dev' ) || + fs_ends_with( $subdomain, '.test' ) || + fs_ends_with( $subdomain, '.staging' ) || + fs_ends_with( $subdomain, '.local' ) || + fs_ends_with( $subdomain, '.example' ) || + fs_ends_with( $subdomain, '.invalid' ) || + // GoDaddy test/dev. + fs_ends_with( $subdomain, '.myftpupload.com' ) || + // ngrok tunneling. + fs_ends_with( $subdomain, '.ngrok.io' ) || + // wpsandbox. + fs_ends_with( $subdomain, '.wpsandbox.pro' ) || + // SiteGround staging. + fs_starts_with( $subdomain, 'staging' ) || + // WPEngine staging. + fs_ends_with( $subdomain, '.staging.wpengine.com' ) || + fs_ends_with( $subdomain, '.dev.wpengine.com' ) || + fs_ends_with( $subdomain, '.wpengine.com' ) || + // Pantheon + ( fs_ends_with( $subdomain, 'pantheonsite.io' ) && + ( fs_starts_with( $subdomain, 'test-' ) || fs_starts_with( $subdomain, 'dev-' ) ) ) || + // Cloudways + fs_ends_with( $subdomain, '.cloudwaysapps.com' ) || + // Kinsta + ( + ( fs_starts_with( $subdomain, 'staging-' ) || fs_starts_with( $subdomain, 'env-' ) ) && + ( fs_ends_with( $subdomain, '.kinsta.com' ) || fs_ends_with( $subdomain, '.kinsta.cloud' ) ) + ) || + // DesktopServer + fs_ends_with( $subdomain, '.dev.cc' ) || + // Pressable + fs_ends_with( $subdomain, '.mystagingwebsite.com' ) || + // WPMU DEV + ( fs_ends_with( $subdomain, '.tempurl.host' ) || fs_ends_with( $subdomain, '.wpmudev.host' ) ) || + // Vendasta + ( fs_ends_with( $subdomain, '.websitepro-staging.com' ) || fs_ends_with( $subdomain, '.websitepro.hosting' ) ) || + // InstaWP + fs_ends_with( $subdomain, '.instawp.xyz' ) + ); + } + + function is_localhost() { + return ( WP_FS__IS_LOCALHOST_FOR_SERVER || self::is_localhost_by_address( $this->url ) ); + } + + /** + * Check if site in trial. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @return bool + */ + function is_trial() { + return is_numeric( $this->trial_plan_id ) && ( strtotime( $this->trial_ends ) > WP_FS__SCRIPT_START_TIME ); + } + + /** + * Check if user already utilized the trial with the current install. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @return bool + */ + function is_trial_utilized() { + return is_numeric( $this->trial_plan_id ); + } + + /** + * @author Edgar Melkonyan + * + * @return bool + */ + function is_beta() { + return ( isset( $this->is_beta ) && true === $this->is_beta ); + } + + /** + * @author Leo Fajardo (@leorw) + * @since 2.5.1 + * + * @param string $site_url + * + * @return bool + */ + function is_clone( $site_url ) { + $clone_install_url = trailingslashit( fs_strip_url_protocol( $this->url ) ); + + return ( $clone_install_url !== $site_url ); + } }\ No newline at end of file
Vulnerability Existed: no Explanation: This diff shows only line ending changes (Unix LF to Unix LF, with consistent formatting). The actual code content remains identical between versions 1.2.11 and 1.2.12. There are no functional changes, security-related modifications, or code logic alterations. The diff represents a whitespace/formatting normalization only, with no security vulnerabilities introduced or fixed.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-subscription.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-subscription.php 2026-01-19 00:17:37.655045280 +0000@@ -1,147 +1,147 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.9- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Subscription extends FS_Entity {-- #region Properties-- /**- * @var number- */- public $user_id;- /**- * @var number- */- public $install_id;- /**- * @var number- */- public $plan_id;- /**- * @var number- */- public $license_id;- /**- * @var float- */- public $total_gross;- /**- * @var float- */- public $amount_per_cycle;- /**- * @var int # of months- */- public $billing_cycle;- /**- * @var float- */- public $outstanding_balance;- /**- * @var int- */- public $failed_payments;- /**- * @var string- */- public $gateway;- /**- * @var string- */- public $external_id;- /**- * @var string|null- */- public $trial_ends;- /**- * @var string|null Datetime of the next payment, or null if cancelled.- */- public $next_payment;- /**- * @since 2.3.1- *- * @var string|null Datetime of the cancellation.- */- public $canceled_at;- /**- * @var string|null- */- public $vat_id;- /**- * @var string Two characters country code- */- public $country_code;-- #endregion Properties-- /**- * @param object|bool $subscription- */- function __construct( $subscription = false ) {- parent::__construct( $subscription );- }-- static function get_type() {- return 'subscription';- }-- /**- * Check if subscription is active.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- function is_active() {- if ( $this->is_canceled() ) {- return false;- }-- return (- ! empty( $this->next_payment ) &&- strtotime( $this->next_payment ) > WP_FS__SCRIPT_START_TIME- );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 2.3.1- *- * @return bool- */- function is_canceled() {- return ! is_null( $this->canceled_at );- }-- /**- * Subscription considered to be new without any payments- * if the next payment should be made within less than 24 hours- * from the subscription creation.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @return bool- */- function is_first_payment_pending() {- return ( WP_FS__TIME_24_HOURS_IN_SEC >= strtotime( $this->next_payment ) - strtotime( $this->created ) );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.7- */- function has_trial() {- return ! is_null( $this->trial_ends );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.9 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Subscription extends FS_Entity { + + #region Properties + + /** + * @var number + */ + public $user_id; + /** + * @var number + */ + public $install_id; + /** + * @var number + */ + public $plan_id; + /** + * @var number + */ + public $license_id; + /** + * @var float + */ + public $total_gross; + /** + * @var float + */ + public $amount_per_cycle; + /** + * @var int # of months + */ + public $billing_cycle; + /** + * @var float + */ + public $outstanding_balance; + /** + * @var int + */ + public $failed_payments; + /** + * @var string + */ + public $gateway; + /** + * @var string + */ + public $external_id; + /** + * @var string|null + */ + public $trial_ends; + /** + * @var string|null Datetime of the next payment, or null if cancelled. + */ + public $next_payment; + /** + * @since 2.3.1 + * + * @var string|null Datetime of the cancellation. + */ + public $canceled_at; + /** + * @var string|null + */ + public $vat_id; + /** + * @var string Two characters country code + */ + public $country_code; + + #endregion Properties + + /** + * @param object|bool $subscription + */ + function __construct( $subscription = false ) { + parent::__construct( $subscription ); + } + + static function get_type() { + return 'subscription'; + } + + /** + * Check if subscription is active. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @return bool + */ + function is_active() { + if ( $this->is_canceled() ) { + return false; + } + + return ( + ! empty( $this->next_payment ) && + strtotime( $this->next_payment ) > WP_FS__SCRIPT_START_TIME + ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 2.3.1 + * + * @return bool + */ + function is_canceled() { + return ! is_null( $this->canceled_at ); + } + + /** + * Subscription considered to be new without any payments + * if the next payment should be made within less than 24 hours + * from the subscription creation. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @return bool + */ + function is_first_payment_pending() { + return ( WP_FS__TIME_24_HOURS_IN_SEC >= strtotime( $this->next_payment ) - strtotime( $this->created ) ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.7 + */ + function has_trial() { + return ! is_null( $this->trial_ends ); + } }\ No newline at end of file
Vulnerability Existed: no No Vulnerabilities Detected - File: inc/freemius/includes/entities/class-fs-subscription.php Explanation: This diff shows only whitespace/line ending changes (converting from Unix LF to potentially different line endings or formatting). The actual code content remains identical between versions 1.2.11 and 1.2.12. No functional code changes, security fixes, or vulnerability introductions are present in this diff. The file contains a subscription entity class with standard property declarations and methods for checking subscription status - no security-sensitive operations or vulnerable patterns are introduced or modified.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/class-fs-user.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/class-fs-user.php 2026-01-19 00:17:37.659045528 +0000@@ -1,73 +1,73 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_User extends FS_Scope_Entity {-- #region Properties-- /**- * @var string- */- public $email;- /**- * @var string- */- public $first;- /**- * @var string- */- public $last;- /**- * @var bool- */- public $is_verified;- /**- * @var string|null- */- public $customer_id;- /**- * @var float- */- public $gross;-- #endregion Properties-- /**- * @param object|bool $user- */- function __construct( $user = false ) {- parent::__construct( $user );- }-- function get_name() {- return trim( ucfirst( trim( is_string( $this->first ) ? $this->first : '' ) ) . ' ' . ucfirst( trim( is_string( $this->last ) ? $this->last : '' ) ) );- }-- function is_verified() {- return ( isset( $this->is_verified ) && true === $this->is_verified );- }-- /**- * @author Leo Fajardo (@leorw)- * @since 2.4.2- *- * @return bool- */- function is_beta() {- // Return `false` since this is just for backward compatibility.- return false;- }-- static function get_type() {- return 'user';- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_User extends FS_Scope_Entity { + + #region Properties + + /** + * @var string + */ + public $email; + /** + * @var string + */ + public $first; + /** + * @var string + */ + public $last; + /** + * @var bool + */ + public $is_verified; + /** + * @var string|null + */ + public $customer_id; + /** + * @var float + */ + public $gross; + + #endregion Properties + + /** + * @param object|bool $user + */ + function __construct( $user = false ) { + parent::__construct( $user ); + } + + function get_name() { + return trim( ucfirst( trim( is_string( $this->first ) ? $this->first : '' ) ) . ' ' . ucfirst( trim( is_string( $this->last ) ? $this->last : '' ) ) ); + } + + function is_verified() { + return ( isset( $this->is_verified ) && true === $this->is_verified ); + } + + /** + * @author Leo Fajardo (@leorw) + * @since 2.4.2 + * + * @return bool + */ + function is_beta() { + // Return `false` since this is just for backward compatibility. + return false; + } + + static function get_type() { + return 'user'; + } }\ No newline at end of file
Vulnerability Existed: no Explanation: This diff shows only formatting changes (line ending conversions from CRLF to LF). The actual code content remains identical between versions 1.2.11 and 1.2.12. No security-relevant code modifications were made. The changes are purely stylistic/whitespace related and do not introduce, fix, or affect any security vulnerabilities.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/entities/index.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/entities/index.php 2026-01-19 00:17:37.659045528 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Vulnerability - File Structure Protection - inc/freemius/includes/entities/index.php [Lines 1-3] Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace/formatting changes (tab vs space normalization) with no functional code modifications. The file serves as a protective index file that prevents direct access and directory listing on unprotected servers by outputting only whitespace/comments. No security vulnerability was introduced or fixed by this change. The file's security purpose remains intact - it continues to prevent information disclosure through directory traversal by providing no meaningful output when directly accessed.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/fs-html-escaping-functions.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/fs-html-escaping-functions.php 2026-01-19 00:17:37.659045528 +0000@@ -1,126 +1,126 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.5.10- */- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- if ( ! function_exists( 'fs_html_get_allowed_kses_list' ) ) {- /**- * Get the allowed KSES list for sanitizing HTML output on the template files.- *- * @return array- */- function fs_html_get_allowed_kses_list() {- $common_attributes = array(- 'id' => true,- 'class' => true,- 'style' => true,- 'data-*' => true,- );-- return array(- 'a' => array_merge(- $common_attributes,- array(- 'href' => true,- 'title' => true,- 'target' => true,- 'rel' => true,- )- ),- 'img' => array_merge(- $common_attributes,- array(- 'src' => true,- 'alt' => true,- 'title' => true,- 'width' => true,- 'height' => true,- )- ),- 'br' => $common_attributes,- 'em' => $common_attributes,- 'small' => $common_attributes,- 'strong' => $common_attributes,- 'u' => $common_attributes,- 'b' => $common_attributes,- 'i' => $common_attributes,- 'hr' => $common_attributes,- 'span' => $common_attributes,- 'p' => $common_attributes,- 'div' => $common_attributes,- 'ul' => $common_attributes,- 'li' => $common_attributes,- 'ol' => $common_attributes,- 'h1' => $common_attributes,- 'h2' => $common_attributes,- 'h3' => $common_attributes,- 'h4' => $common_attributes,- 'h5' => $common_attributes,- 'h6' => $common_attributes,- 'button' => $common_attributes,- 'sup' => $common_attributes,- 'sub' => $common_attributes,- 'nobr' => $common_attributes,- );- }- }-- if ( ! function_exists( 'fs_html_get_classname' ) ) {- /**- * Gets an HTML class attribute value.- *- * @param string|string[] $classes- *- * @return string- */- function fs_html_get_classname( $classes ) {- if ( is_array( $classes ) ) {- $classes = implode( ' ', $classes );- }-- return esc_attr( $classes );- }- }-- if ( ! function_exists( 'fs_html_get_attributes' ) ) {- /**- * Gets a properly escaped HTML attributes string from an associative array.- *- * @param array<string, string> $attributes A key/value pair array of attributes.- *- * @return string- */- function fs_html_get_attributes( $attributes ) {- $attribute_string = '';-- foreach ( $attributes as $key => $value ) {- $attribute_string .= sprintf(- ' %1$s="%2$s"',- esc_attr( $key ),- esc_attr( $value )- );- }-- return $attribute_string;- }- }-- if ( ! function_exists( 'fs_html_get_sanitized_html' ) ) {- /**- * Get sanitized HTML for template files.- *- * @param string $raw_html- *- * @return string- * @since 2.5.10- */- function fs_html_get_sanitized_html( $raw_html ) {- return wp_kses( $raw_html, fs_html_get_allowed_kses_list() );- }- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.5.10 + */ + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + if ( ! function_exists( 'fs_html_get_allowed_kses_list' ) ) { + /** + * Get the allowed KSES list for sanitizing HTML output on the template files. + * + * @return array + */ + function fs_html_get_allowed_kses_list() { + $common_attributes = array( + 'id' => true, + 'class' => true, + 'style' => true, + 'data-*' => true, + ); + + return array( + 'a' => array_merge( + $common_attributes, + array( + 'href' => true, + 'title' => true, + 'target' => true, + 'rel' => true, + ) + ), + 'img' => array_merge( + $common_attributes, + array( + 'src' => true, + 'alt' => true, + 'title' => true, + 'width' => true, + 'height' => true, + ) + ), + 'br' => $common_attributes, + 'em' => $common_attributes, + 'small' => $common_attributes, + 'strong' => $common_attributes, + 'u' => $common_attributes, + 'b' => $common_attributes, + 'i' => $common_attributes, + 'hr' => $common_attributes, + 'span' => $common_attributes, + 'p' => $common_attributes, + 'div' => $common_attributes, + 'ul' => $common_attributes, + 'li' => $common_attributes, + 'ol' => $common_attributes, + 'h1' => $common_attributes, + 'h2' => $common_attributes, + 'h3' => $common_attributes, + 'h4' => $common_attributes, + 'h5' => $common_attributes, + 'h6' => $common_attributes, + 'button' => $common_attributes, + 'sup' => $common_attributes, + 'sub' => $common_attributes, + 'nobr' => $common_attributes, + ); + } + } + + if ( ! function_exists( 'fs_html_get_classname' ) ) { + /** + * Gets an HTML class attribute value. + * + * @param string|string[] $classes + * + * @return string + */ + function fs_html_get_classname( $classes ) { + if ( is_array( $classes ) ) { + $classes = implode( ' ', $classes ); + } + + return esc_attr( $classes ); + } + } + + if ( ! function_exists( 'fs_html_get_attributes' ) ) { + /** + * Gets a properly escaped HTML attributes string from an associative array. + * + * @param array<string, string> $attributes A key/value pair array of attributes. + * + * @return string + */ + function fs_html_get_attributes( $attributes ) { + $attribute_string = ''; + + foreach ( $attributes as $key => $value ) { + $attribute_string .= sprintf( + ' %1$s="%2$s"', + esc_attr( $key ), + esc_attr( $value ) + ); + } + + return $attribute_string; + } + } + + if ( ! function_exists( 'fs_html_get_sanitized_html' ) ) { + /** + * Get sanitized HTML for template files. + * + * @param string $raw_html + * + * @return string + * @since 2.5.10 + */ + function fs_html_get_sanitized_html( $raw_html ) { + return wp_kses( $raw_html, fs_html_get_allowed_kses_list() ); + } + }
Vulnerability Existed: no No Vulnerability - Line Ending Conversion Only Old Code: Unix line endings (LF - \n) Fixed Code: Windows line endings (CRLF - \r\n) Explanation: This diff shows only a line ending conversion from LF (Unix/Linux style) to CRLF (Windows style). The actual code content remains identical - no functional changes, logic modifications, or security fixes have been applied. All HTML escaping functions, sanitization methods, and security controls remain unchanged. This is purely a formatting change at the file level and does not address or introduce any security vulnerabilities.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/index.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/index.php 2026-01-19 00:17:37.659045528 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no Explanation: This diff contains only whitespace/formatting changes (likely line ending normalization, such as converting CRLF to LF or adjusting trailing spaces). The actual content and functionality remain identical: - Line 1: `<?php` opening tag - unchanged - Line 2: Comment "Silence is golden." - unchanged - Line 3: Comment about hiding file structure - unchanged The `index.php` file in the `/inc/freemius/includes/` directory serves as a security measure by itself (an empty or comment-only PHP file prevents direct directory access and information disclosure). No security vulnerability was introduced or fixed by this change, as the protective mechanism remains intact. No CWE applies to this diff.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/l10n.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/l10n.php 2026-01-19 00:17:37.659045528 +0000@@ -1,48 +1,48 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.1.6- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Retrieve the translation of $text.- *- * @since 1.2.1.6- *- * @param string $text- * - * @return string- */- function _fs_text( $text ) {- // Avoid misleading Theme Check warning.- $fn = 'translate';- return $fn( $text, 'freemius' );- }-- /**- * Retrieve translated string with gettext context.- *- * Quite a few times, there will be collisions with similar translatable text- * found in more than two places, but with different translated context.- *- * By including the context in the pot file, translators can translate the two- * strings differently.- *- * @since 1.2.1.6- *- * @param string $text- * @param string $context - * - * @return string- */- function _fs_x( $text, $context ) {- // Avoid misleading Theme Check warning.- $fn = 'translate_with_gettext_context';- return $fn( $text, $context, 'freemius' );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.1.6 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Retrieve the translation of $text. + * + * @since 1.2.1.6 + * + * @param string $text + * + * @return string + */ + function _fs_text( $text ) { + // Avoid misleading Theme Check warning. + $fn = 'translate'; + return $fn( $text, 'freemius' ); + } + + /** + * Retrieve translated string with gettext context. + * + * Quite a few times, there will be collisions with similar translatable text + * found in more than two places, but with different translated context. + * + * By including the context in the pot file, translators can translate the two + * strings differently. + * + * @since 1.2.1.6 + * + * @param string $text + * @param string $context + * + * @return string + */ + function _fs_x( $text, $context ) { + // Avoid misleading Theme Check warning. + $fn = 'translate_with_gettext_context'; + return $fn( $text, $context, 'freemius' ); + }
Vulnerability Existed: no No Security Vulnerabilities Detected - inc/freemius/includes/l10n.php Explanation: The diff shows only whitespace/line ending changes (CRLF to LF conversion). The actual code content remains identical: - Both versions define the same two translation wrapper functions: `_fs_text()` and `_fs_x()` - Both functions use dynamic function calls (`$fn()`) to invoke WordPress translation functions, which is a legitimate pattern to avoid Theme Check warnings - The functions properly pass the 'freemius' text domain - No functional code changes, no new vulnerabilities introduced, and no existing vulnerabilities fixed - The line ending normalization does not affect security This appears to be a formatting/cleanup commit with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/managers/class-fs-admin-menu-manager.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/managers/class-fs-admin-menu-manager.php 2026-01-19 00:17:37.659045528 +0000@@ -1,1006 +1,1006 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Admin_Menu_Manager {-- #region Properties-- /**- * @since 1.2.2- *- * @var string- */- protected $_module_unique_affix;-- /**- * @since 1.2.2- *- * @var number- */- protected $_module_id;-- /**- * @since 1.2.2- *- * @var string- */- protected $_module_type;-- /**- * @since 1.0.6- *- * @var string- */- private $_menu_slug;- /**- * @since 1.1.3- *- * @var string- */- private $_parent_slug;- /**- * @since 1.1.3- *- * @var string- */- private $_parent_type;- /**- * @since 1.1.3- *- * @var string- */- private $_type;- /**- * @since 1.1.3- *- * @var bool- */- private $_is_top_level;- /**- * @since 1.1.3- *- * @var bool- */- private $_is_override_exact;- /**- * @since 1.1.3- *- * @var array<string,bool>- */- private $_default_submenu_items;- /**- * @since 1.1.3- *- * @var string- */- private $_first_time_path;- /**- * @since 1.2.2- *- * @var bool- */- private $_menu_exists;- /**- * @since 2.0.0- *- * @var bool- */- private $_network_menu_exists;-- #endregion Properties-- /**- * @var FS_Logger- */- protected $_logger;-- #region Singleton-- /**- * @var FS_Admin_Menu_Manager[]- */- private static $_instances = array();-- /**- * @param number $module_id- * @param string $module_type- * @param string $module_unique_affix- *- * @return FS_Admin_Menu_Manager- */- static function instance( $module_id, $module_type, $module_unique_affix ) {- $key = 'm_' . $module_id;-- if ( ! isset( self::$_instances[ $key ] ) ) {- self::$_instances[ $key ] = new FS_Admin_Menu_Manager( $module_id, $module_type, $module_unique_affix );- }-- return self::$_instances[ $key ];- }-- protected function __construct( $module_id, $module_type, $module_unique_affix ) {- $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $module_id . '_admin_menu', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );-- $this->_module_id = $module_id;- $this->_module_type = $module_type;- $this->_module_unique_affix = $module_unique_affix;- }-- #endregion Singleton-- #region Helpers-- private function get_option( &$options, $key, $default = false ) {- return ! empty( $options[ $key ] ) ? $options[ $key ] : $default;- }-- private function get_bool_option( &$options, $key, $default = false ) {- return isset( $options[ $key ] ) && is_bool( $options[ $key ] ) ? $options[ $key ] : $default;- }-- #endregion Helpers-- /**- * @param array $menu- * @param bool $is_addon- */- function init( $menu, $is_addon = false ) {- $this->_menu_exists = ( isset( $menu['slug'] ) && ! empty( $menu['slug'] ) );- $this->_network_menu_exists = ( ! empty( $menu['network'] ) && true === $menu['network'] );-- $this->_menu_slug = ( $this->_menu_exists ? $menu['slug'] : $this->_module_unique_affix );-- $this->_default_submenu_items = array();- // @deprecated- $this->_type = 'page';- $this->_is_top_level = true;- $this->_is_override_exact = false;- $this->_parent_slug = false;- // @deprecated- $this->_parent_type = 'page';-- if ( isset( $menu ) ) {- if ( ! $is_addon ) {- $this->_default_submenu_items = array(- 'contact' => $this->get_bool_option( $menu, 'contact', true ),- 'support' => $this->get_bool_option( $menu, 'support', true ),- 'affiliation' => $this->get_bool_option( $menu, 'affiliation', true ),- 'account' => $this->get_bool_option( $menu, 'account', true ),- 'pricing' => $this->get_bool_option( $menu, 'pricing', true ),- 'addons' => $this->get_bool_option( $menu, 'addons', true ),- );-- // @deprecated- $this->_type = $this->get_option( $menu, 'type', 'page' );- }-- $this->_is_override_exact = $this->get_bool_option( $menu, 'override_exact' );-- if ( isset( $menu['parent'] ) ) {- $this->_parent_slug = $this->get_option( $menu['parent'], 'slug' );- // @deprecated- $this->_parent_type = $this->get_option( $menu['parent'], 'type', 'page' );-- // If parent's slug is different, then it's NOT a top level menu item.- $this->_is_top_level = ( $this->_parent_slug === $this->_menu_slug );- } else {- /**- * If no parent then top level if:- * - Has custom admin menu ('page')- * - CPT menu type ('cpt')- */-// $this->_is_top_level = in_array( $this->_type, array(-// 'cpt',-// 'page'-// ) );- }-- $first_path = $this->get_option( $menu, 'first-path', false );-- if ( ! empty( $first_path ) && is_string( $first_path ) ) {- $this->_first_time_path = $first_path;- }- }- }-- /**- * Check if top level menu.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return bool False if submenu item.- */- function is_top_level() {- return $this->_is_top_level;- }-- /**- * Check if the page should be override on exact URL match.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return bool False if submenu item.- */- function is_override_exact() {- return $this->_is_override_exact;- }--- /**- * Get the path of the page the user should be forwarded to after first activation.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @param bool $is_network Since 2.4.5- *- * @return string- */- function get_first_time_path( $is_network = false ) {- if ( empty ( $this->_first_time_path ) ) {- return $this->_first_time_path;- }-- if ( $is_network ) {- return network_admin_url( $this->_first_time_path );- } else {- return admin_url( $this->_first_time_path );- }- }-- /**- * Check if plugin's menu item is part of a custom top level menu.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return bool- */- function has_custom_parent() {- return ! $this->_is_top_level && is_string( $this->_parent_slug );- }-- /**- * @author Leo Fajardo (@leorw)- * @since 1.2.2- *- * @return bool- */- function has_menu() {- return $this->_menu_exists;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @return bool- */- function has_network_menu() {- return $this->_network_menu_exists;- }-- /**- * @author Leo Fajardo (@leorw)- *- * @param string $menu_slug- *- * @since 2.1.3- */- function set_slug_and_network_menu_exists_flag($menu_slug ) {- $this->_menu_slug = $menu_slug;- $this->_network_menu_exists = false;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @param string $id- * @param bool $default- * @param bool $ignore_menu_existence Since 1.2.2.7 If true, check if the submenu item visible even if there's no parent menu.- *- * @return bool- */- function is_submenu_item_visible( $id, $default = true, $ignore_menu_existence = false ) {- if ( ! $ignore_menu_existence && ! $this->has_menu() ) {- return false;- }-- return fs_apply_filter(- $this->_module_unique_affix,- 'is_submenu_visible',- $this->get_bool_option( $this->_default_submenu_items, $id, $default ),- $id- );- }-- /**- * Calculates admin settings menu slug.- * If plugin's menu slug is a file (e.g. CPT), uses plugin's slug as the menu slug.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @param string $page- *- * @return string- */- function get_slug( $page = '' ) {- return ( ( false === strpos( $this->_menu_slug, '.php?' ) ) ?- $this->_menu_slug :- $this->_module_unique_affix ) . ( empty( $page ) ? '' : ( '-' . $page ) );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return string- */- function get_parent_slug() {- return $this->_parent_slug;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return string- */- function get_type() {- return $this->_type;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return bool- */- function is_cpt() {- return ( 0 === strpos( $this->_menu_slug, 'edit.php?post_type=' ) ||- // Back compatibility.- 'cpt' === $this->_type- );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return string- */- function get_parent_type() {- return $this->_parent_type;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return string- */- function get_raw_slug() {- return $this->_menu_slug;- }-- /**- * Get plugin's original menu slug.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return string- */- function get_original_menu_slug() {- if ( 'cpt' === $this->_type ) {- return add_query_arg( array(- 'post_type' => $this->_menu_slug- ), 'edit.php' );- }-- if ( false === strpos( $this->_menu_slug, '.php?' ) ) {- return $this->_menu_slug;- } else {- return $this->_module_unique_affix;- }- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @return string- */- function get_top_level_menu_slug() {- return $this->has_custom_parent() ?- $this->get_parent_slug() :- $this->get_raw_slug();- }-- /**- * Is user on plugin's admin activation page.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.8- *- * @param bool $show_opt_in_on_themes_page Since 2.3.1- *- * @return bool- *- * @deprecated Please use is_activation_page() instead.- */- function is_main_settings_page( $show_opt_in_on_themes_page = false ) {- return $this->is_activation_page( $show_opt_in_on_themes_page );- }-- /**- * Is user on product's admin activation page.- *- * @author Vova Feldman (@svovaf)- * @since 2.3.1- *- * @param bool $show_opt_in_on_themes_page Since 2.3.1- *- * @return bool- */- function is_activation_page( $show_opt_in_on_themes_page = false ) {- if ( $show_opt_in_on_themes_page ) {- /**- * In activation only when show_optin query string param is given.- *- * @since 1.2.2- */- return (- ( WP_FS__MODULE_TYPE_THEME === $this->_module_type ) &&- Freemius::is_themes_page() &&- fs_request_get_bool( $this->_module_unique_affix . '_show_optin' )- );- }-- if ( $this->_menu_exists &&- ( fs_is_plugin_page( $this->_menu_slug ) || fs_is_plugin_page( $this->_module_unique_affix ) )- ) {- /**- * Module has a settings menu and the context page is the main settings page, so assume it's in- * activation (doesn't really check if already opted-in/skipped or not).- *- * @since 1.2.2- */- return true;- }-- return false;- }-- #region Submenu Override-- /**- * Override submenu's action.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.0- *- * @param string $parent_slug- * @param string $menu_slug- * @param callable $function- *- * @return false|string If submenu exist, will return the hook name.- */- function override_submenu_action( $parent_slug, $menu_slug, $function ) {- global $submenu;-- $menu_slug = plugin_basename( $menu_slug );- $parent_slug = plugin_basename( $parent_slug );-- if ( ! isset( $submenu[ $parent_slug ] ) ) {- // Parent menu not exist.- return false;- }-- $found_submenu_item = false;- foreach ( $submenu[ $parent_slug ] as $submenu_item ) {- if ( $menu_slug === $submenu_item[2] ) {- $found_submenu_item = $submenu_item;- break;- }- }-- if ( false === $found_submenu_item ) {- // Submenu item not found.- return false;- }-- // Remove current function.- $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug );- remove_all_actions( $hookname );-- // Attach new action.- add_action( $hookname, $function );-- return $hookname;- }-- #endregion Submenu Override-- #region Top level menu Override-- /**- * Find plugin's admin dashboard main menu item.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.2- *- * @return string[]|false- */- private function find_top_level_menu() {- global $menu;-- $position = - 1;- $found_menu = false;-- $menu_slug = $this->get_raw_slug();-- $hook_name = get_plugin_page_hookname( $menu_slug, '' );- foreach ( $menu as $pos => $m ) {- if ( $menu_slug === $m[2] ) {- $position = $pos;- $found_menu = $m;- break;- }- }-- if ( false === $found_menu ) {- return false;- }-- return array(- 'menu' => $found_menu,- 'position' => $position,- 'hook_name' => $hook_name- );- }-- /**- * Find plugin's admin dashboard main submenu item.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.6- *- * @return array|false- */- private function find_main_submenu() {- global $submenu;-- $top_level_menu_slug = $this->get_top_level_menu_slug();-- if ( ! isset( $submenu[ $top_level_menu_slug ] ) ) {- return false;- }-- $submenu_slug = $this->get_raw_slug();-- $position = - 1;- $found_submenu = false;-- $hook_name = get_plugin_page_hookname( $submenu_slug, '' );-- foreach ( $submenu[ $top_level_menu_slug ] as $pos => $sub ) {- if ( $submenu_slug === $sub[2] ) {- $position = $pos;- $found_submenu = $sub;- }- }-- if ( false === $found_submenu ) {- return false;- }-- return array(- 'menu' => $found_submenu,- 'parent_slug' => $top_level_menu_slug,- 'position' => $position,- 'hook_name' => $hook_name- );- }-- /**- * Remove all sub-menu items.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @return bool If submenu with plugin's menu slug was found.- */- private function remove_all_submenu_items() {- global $submenu;-- $menu_slug = $this->get_raw_slug();-- if ( ! isset( $submenu[ $menu_slug ] ) ) {- return false;- }-- /**- * This method is NOT executed for WordPress.org themes.- * Since we maintain only one version of the SDK we added this small- * hack to avoid the error from Theme Check since it's a false-positive.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2.7- */- $submenu_ref = &$submenu;- $submenu_ref[ $menu_slug ] = array();-- return true;- }-- /**- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @param bool $remove_top_level_menu- * - * @return false|array[string]mixed- */- function remove_menu_item( $remove_top_level_menu = false ) {- $this->_logger->entrance();-- // Find main menu item.- $top_level_menu = $this->find_top_level_menu();-- if ( false === $top_level_menu ) {- return false;- }-- // Remove it with its actions.- remove_all_actions( $top_level_menu['hook_name'] );-- // Remove all submenu items.- $this->remove_all_submenu_items();-- if ( $remove_top_level_menu ) {- global $menu;- unset( $menu[ $top_level_menu['position'] ] );- }-- return $top_level_menu;- }-- /**- * Get module's main admin setting page URL.- *- * @todo This method was only tested for wp.org compliant themes with a submenu item. Need to test for plugins with top level, submenu, and CPT top level, menu items.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2.7- *- * @return string- */- function main_menu_url() {- $this->_logger->entrance();-- if ( $this->_is_top_level ) {- $menu = $this->find_top_level_menu();- } else {- $menu = $this->find_main_submenu();- }-- $parent_slug = isset( $menu['parent_slug'] ) ?- $menu['parent_slug'] :- 'admin.php';-- return admin_url(- $parent_slug .- ( false === strpos( $parent_slug, '?' ) ? '?' : '&' ) .- 'page=' .- $menu['menu'][2]- );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.4- *- * @param callable $function- *- * @return false|array[string]mixed- */- function override_menu_item( $function ) {- $found_menu = $this->remove_menu_item();-- if ( false === $found_menu ) {- return false;- }-- if ( ! $this->is_top_level() || ! $this->is_cpt() ) {- $menu_slug = plugin_basename( $this->get_slug() );-- $hookname = get_plugin_page_hookname( $menu_slug, '' );-- // Override menu action.- add_action( $hookname, $function );- } else {- global $menu;-- // Remove original CPT menu.- unset( $menu[ $found_menu['position'] ] );-- // Create new top-level menu action.- $hookname = self::add_page(- $found_menu['menu'][3],- $found_menu['menu'][0],- 'manage_options',- $this->get_slug(),- $function,- $found_menu['menu'][6],- $found_menu['position']- );- }-- return $hookname;- }-- /**- * Adds a counter to the module's top level menu item.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.5- *- * @param int $counter- * @param string $class- */- function add_counter_to_menu_item( $counter = 1, $class = '' ) {- global $menu, $submenu;-- $mask = '%s <span class="update-plugins %s count-%3$s" aria-hidden="true"><span>%3$s<span class="screen-reader-text">%3$s notifications</span></span></span>';-- /**- * This method is NOT executed for WordPress.org themes.- * Since we maintain only one version of the SDK we added this small- * hack to avoid the error from Theme Check since it's a false-positive.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2.7- */- $menu_ref = &$menu;- $submenu_ref = &$submenu;-- if ( $this->_is_top_level ) {- // Find main menu item.- $found_menu = $this->find_top_level_menu();-- if ( false !== $found_menu ) {- // Override menu label.- $menu_ref[ $found_menu['position'] ][0] = sprintf(- $mask,- $found_menu['menu'][0],- $class,- $counter- );- }- } else {- $found_submenu = $this->find_main_submenu();-- if ( false !== $found_submenu ) {- // Override menu label.- $submenu_ref[ $found_submenu['parent_slug'] ][ $found_submenu['position'] ][0] = sprintf(- $mask,- $found_submenu['menu'][0],- $class,- $counter- );- }- }- }-- #endregion Top level menu Override-- /**- * Add a top-level menu page.- *- * Note for WordPress.org Theme/Plugin reviewer:- *- * This is a replication of `add_menu_page()` to avoid Theme Check warning.- *- * Why?- * ====- * Freemius is an SDK for plugin and theme developers. Since the core- * of the SDK is relevant both for plugins and themes, for obvious reasons,- * we only develop and maintain one code base.- *- * This method will not run for wp.org themes (only plugins) since theme- * admin settings/options are now only allowed in the customizer.- *- * If you have any questions or need clarifications, please don't hesitate- * pinging me on slack, my username is @svovaf.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2- *- * @param string $page_title The text to be displayed in the title tags of the page when the menu is- * selected.- * @param string $menu_title The text to be used for the menu.- * @param string $capability The capability required for this menu to be displayed to the user.- * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu).- * @param callable|string $function The function to be called to output the content for this page.- * @param string $icon_url The URL to the icon to be used for this menu.- * * Pass a base64-encoded SVG using a data URI, which will be colored to- * match the color scheme. This should begin with- * 'data:image/svg+xml;base64,'.- * * Pass the name of a Dashicons helper class to use a font icon,- * e.g. 'dashicons-chart-pie'.- * * Pass 'none' to leave div.wp-menu-image empty so an icon can be added- * via CSS.- * @param int $position The position in the menu order this one should appear.- *- * @return string The resulting page's hook_suffix.- */- static function add_page(- $page_title,- $menu_title,- $capability,- $menu_slug,- $function = '',- $icon_url = '',- $position = null- ) {- $fn = 'add_menu' . '_page';-- return $fn(- $page_title,- $menu_title,- $capability,- $menu_slug,- $function,- $icon_url,- $position- );- }-- /**- * Add page and update menu instance settings.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param string $page_title- * @param string $menu_title- * @param string $capability- * @param string $menu_slug- * @param callable|string $function- * @param string $icon_url- * @param int|null $position- *- * @return string- */- function add_page_and_update(- $page_title,- $menu_title,- $capability,- $menu_slug,- $function = '',- $icon_url = '',- $position = null- ) {- $this->_menu_slug = $menu_slug;- $this->_is_top_level = true;- $this->_menu_exists = true;- $this->_network_menu_exists = true;-- return self::add_page(- $page_title,- $menu_title,- $capability,- $menu_slug,- $function,- $icon_url,- $position- );- }-- /**- * Add a submenu page.- *- * Note for WordPress.org Theme/Plugin reviewer:- *- * This is a replication of `add_submenu_page()` to avoid Theme Check warning.- *- * Why?- * ====- * Freemius is an SDK for plugin and theme developers. Since the core- * of the SDK is relevant both for plugins and themes, for obvious reasons,- * we only develop and maintain one code base.- *- * This method will not run for wp.org themes (only plugins) since theme- * admin settings/options are now only allowed in the customizer.- *- * If you have any questions or need clarifications, please don't hesitate- * pinging me on slack, my username is @svovaf.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2- *- * @param string $parent_slug The slug name for the parent menu (or the file name of a standard- * WordPress admin page).- * @param string $page_title The text to be displayed in the title tags of the page when the menu is- * selected.- * @param string $menu_title The text to be used for the menu.- * @param string $capability The capability required for this menu to be displayed to the user.- * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu).- * @param callable|string $function The function to be called to output the content for this page.- *- * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability- * required.- */- static function add_subpage(- $parent_slug,- $page_title,- $menu_title,- $capability,- $menu_slug,- $function = ''- ) {- $fn = 'add_submenu' . '_page';-- return $fn( $parent_slug,- $page_title,- $menu_title,- $capability,- $menu_slug,- $function- );- }-- /**- * Add sub page and update menu instance settings.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param string $parent_slug- * @param string $page_title- * @param string $menu_title- * @param string $capability- * @param string $menu_slug- * @param callable|string $function- *- * @return string- */- function add_subpage_and_update(- $parent_slug,- $page_title,- $menu_title,- $capability,- $menu_slug,- $function = ''- ) {- $this->_menu_slug = $menu_slug;- $this->_parent_slug = $parent_slug;- $this->_is_top_level = false;- $this->_menu_exists = true;- $this->_network_menu_exists = true;-- return self::add_subpage(
Let me examine the diff content more carefully. The diff shows changes from version 1.2.11 to 1.2.12 of the file `class-fs-admin-menu-manager.php`. Looking at the provided diff, I can see the line numbers are being changed (indicated by the `-` and `+` prefixes), but the actual code content appears to be identical - this is a whitespace or formatting change only. **Analysis Result:** Vulnerability Existed: no The provided diff shows a version bump from 1.2.11 to 1.2.12 in the file `inc/freemius/includes/managers/class-fs-admin-menu-manager.php`. The diff content indicates line-by-line changes (marked with `-` for old and `+` for new), but examining the actual code snippets shown: - The code structure, logic, and functionality remain unchanged - No new code has been introduced - No code has been removed or altered - The changes appear to be formatting/whitespace related only **Explanation:** No security vulnerabilities were introduced or fixed in this diff. The changes represent a version update without functional code modifications. The file maintains the same security posture before and after the update. All existing security considerations (input validation, capability checks with `manage_options`, proper use of WordPress hooks and global variables) remain consistent throughout. Since the diff shows no actual code changes (only version/metadata updates), there are no security fixes to report.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/managers/class-fs-cache-manager.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/managers/class-fs-cache-manager.php 2026-01-19 00:17:37.659045528 +0000@@ -1,326 +1,326 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.6- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Cache_Manager {- /**- * @var FS_Option_Manager- */- private $_options;- /**- * @var FS_Logger- */- private $_logger;-- /**- * @var FS_Cache_Manager[]- */- private static $_MANAGERS = array();-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.3- *- * @param string $id- */- private function __construct( $id ) {- $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_cach_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );-- $this->_logger->entrance();- $this->_logger->log( 'id = ' . $id );-- $this->_options = FS_Option_Manager::get_manager( $id, true, true, false );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.6- *- * @param $id- *- * @return FS_Cache_Manager- */- static function get_manager( $id ) {- $id = strtolower( $id );-- if ( ! isset( self::$_MANAGERS[ $id ] ) ) {- self::$_MANAGERS[ $id ] = new FS_Cache_Manager( $id );- }-- return self::$_MANAGERS[ $id ];- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.6- *- * @return bool- */- function is_empty() {- $this->_logger->entrance();-- return $this->_options->is_empty();- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.6- */- function clear() {- $this->_logger->entrance();-- $this->_options->clear( true );- }-- /**- * Delete cache manager from DB.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- */- function delete() {- $this->_options->delete();- }-- /**- * Check if there's a cached item.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.6- *- * @param string $key- *- * @return bool- */- function has( $key ) {- $cache_entry = $this->_options->get_option( $key, false );-- return ( is_object( $cache_entry ) &&- isset( $cache_entry->timestamp ) &&- is_numeric( $cache_entry->timestamp )- );- }-- /**- * Check if there's a valid cached item.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.6- *- * @param string $key- * @param null|int $expiration Since 1.2.2.7- *- * @return bool- */- function has_valid( $key, $expiration = null ) {- $cache_entry = $this->_options->get_option( $key, false );-- $is_valid = ( is_object( $cache_entry ) &&- isset( $cache_entry->timestamp ) &&- is_numeric( $cache_entry->timestamp ) &&- $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME- );-- if ( $is_valid &&- is_numeric( $expiration ) &&- isset( $cache_entry->created ) &&- is_numeric( $cache_entry->created ) &&- $cache_entry->created + $expiration < WP_FS__SCRIPT_START_TIME- ) {- /**- * Even if the cache is still valid, since we are checking for validity- * with an explicit expiration period, if the period has past, return- * `false` as if the cache is invalid.- *- * @since 1.2.2.7- */- $is_valid = false;- }-- return $is_valid;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.6- *- * @param string $key- * @param mixed $default- *- * @return mixed- */- function get( $key, $default = null ) {- $this->_logger->entrance( 'key = ' . $key );-- $cache_entry = $this->_options->get_option( $key, false );-- if ( is_object( $cache_entry ) &&- isset( $cache_entry->timestamp ) &&- is_numeric( $cache_entry->timestamp )- ) {- return $cache_entry->result;- }-- return is_object( $default ) ? clone $default : $default;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.6- *- * @param string $key- * @param mixed $default- *- * @return mixed- */- function get_valid( $key, $default = null ) {- $this->_logger->entrance( 'key = ' . $key );-- $cache_entry = $this->_options->get_option( $key, false );-- if ( is_object( $cache_entry ) &&- isset( $cache_entry->timestamp ) &&- is_numeric( $cache_entry->timestamp ) &&- $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME- ) {- return $cache_entry->result;- }-- return is_object( $default ) ? clone $default : $default;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.1.6- *- * @param string $key- * @param mixed $value- * @param int $expiration- * @param int $created Since 2.0.0 Cache creation date.- */- function set( $key, $value, $expiration = WP_FS__TIME_24_HOURS_IN_SEC, $created = WP_FS__SCRIPT_START_TIME ) {- $this->_logger->entrance( 'key = ' . $key );-- $cache_entry = new stdClass();-- $cache_entry->result = $value;- $cache_entry->created = $created;- $cache_entry->timestamp = $created + $expiration;- $this->_options->set_option( $key, $cache_entry, true );- }-- /**- * Get cached record expiration, or false if not cached or expired.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.7.3- *- * @param string $key- *- * @return bool|int- */- function get_record_expiration( $key ) {- $this->_logger->entrance( 'key = ' . $key );-- $cache_entry = $this->_options->get_option( $key, false );-- if ( is_object( $cache_entry ) &&- isset( $cache_entry->timestamp ) &&- is_numeric( $cache_entry->timestamp ) &&- $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME- ) {- return $cache_entry->timestamp;- }-- return false;- }-- /**- * Purge cached item.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.6- *- * @param string $key- */- function purge( $key ) {- $this->_logger->entrance( 'key = ' . $key );-- $this->_options->unset_option( $key, true );- }-- /**- * Extend cached item caching period.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @param string $key- * @param int $expiration- *- * @return bool- */- function update_expiration( $key, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {- $this->_logger->entrance( 'key = ' . $key );-- $cache_entry = $this->_options->get_option( $key, false );-- if ( ! is_object( $cache_entry ) ||- ! isset( $cache_entry->timestamp ) ||- ! is_numeric( $cache_entry->timestamp )- ) {- return false;- }-- $this->set( $key, $cache_entry->result, $expiration, $cache_entry->created );-- return true;- }-- /**- * Set cached item as expired.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2.7- *- * @param string $key- */- function expire( $key ) {- $this->_logger->entrance( 'key = ' . $key );-- $cache_entry = $this->_options->get_option( $key, false );-- if ( is_object( $cache_entry ) &&- isset( $cache_entry->timestamp ) &&- is_numeric( $cache_entry->timestamp )- ) {- // Set to expired.- $cache_entry->timestamp = WP_FS__SCRIPT_START_TIME;- $this->_options->set_option( $key, $cache_entry, true );- }- }-- #--------------------------------------------------------------------------------- #region Migration- #---------------------------------------------------------------------------------- /**- * Migrate options from site level.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- */- function migrate_to_network() {- $this->_options->migrate_to_network();- }-- #endregion+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.6 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Cache_Manager { + /** + * @var FS_Option_Manager + */ + private $_options; + /** + * @var FS_Logger + */ + private $_logger; + + /** + * @var FS_Cache_Manager[] + */ + private static $_MANAGERS = array(); + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.3 + * + * @param string $id + */ + private function __construct( $id ) { + $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_cach_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK ); + + $this->_logger->entrance(); + $this->_logger->log( 'id = ' . $id ); + + $this->_options = FS_Option_Manager::get_manager( $id, true, true, false ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + * + * @param $id + * + * @return FS_Cache_Manager + */ + static function get_manager( $id ) { + $id = strtolower( $id ); + + if ( ! isset( self::$_MANAGERS[ $id ] ) ) { + self::$_MANAGERS[ $id ] = new FS_Cache_Manager( $id ); + } + + return self::$_MANAGERS[ $id ]; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + * + * @return bool + */ + function is_empty() { + $this->_logger->entrance(); + + return $this->_options->is_empty(); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + */ + function clear() { + $this->_logger->entrance(); + + $this->_options->clear( true ); + } + + /** + * Delete cache manager from DB. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + */ + function delete() { + $this->_options->delete(); + } + + /** + * Check if there's a cached item. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + * + * @param string $key + * + * @return bool + */ + function has( $key ) { + $cache_entry = $this->_options->get_option( $key, false ); + + return ( is_object( $cache_entry ) && + isset( $cache_entry->timestamp ) && + is_numeric( $cache_entry->timestamp ) + ); + } + + /** + * Check if there's a valid cached item. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + * + * @param string $key + * @param null|int $expiration Since 1.2.2.7 + * + * @return bool + */ + function has_valid( $key, $expiration = null ) { + $cache_entry = $this->_options->get_option( $key, false ); + + $is_valid = ( is_object( $cache_entry ) && + isset( $cache_entry->timestamp ) && + is_numeric( $cache_entry->timestamp ) && + $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME + ); + + if ( $is_valid && + is_numeric( $expiration ) && + isset( $cache_entry->created ) && + is_numeric( $cache_entry->created ) && + $cache_entry->created + $expiration < WP_FS__SCRIPT_START_TIME + ) { + /** + * Even if the cache is still valid, since we are checking for validity + * with an explicit expiration period, if the period has past, return + * `false` as if the cache is invalid. + * + * @since 1.2.2.7 + */ + $is_valid = false; + } + + return $is_valid; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + function get( $key, $default = null ) { + $this->_logger->entrance( 'key = ' . $key ); + + $cache_entry = $this->_options->get_option( $key, false ); + + if ( is_object( $cache_entry ) && + isset( $cache_entry->timestamp ) && + is_numeric( $cache_entry->timestamp ) + ) { + return $cache_entry->result; + } + + return is_object( $default ) ? clone $default : $default; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + function get_valid( $key, $default = null ) { + $this->_logger->entrance( 'key = ' . $key ); + + $cache_entry = $this->_options->get_option( $key, false ); + + if ( is_object( $cache_entry ) && + isset( $cache_entry->timestamp ) && + is_numeric( $cache_entry->timestamp ) && + $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME + ) { + return $cache_entry->result; + } + + return is_object( $default ) ? clone $default : $default; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + * + * @param string $key + * @param mixed $value + * @param int $expiration + * @param int $created Since 2.0.0 Cache creation date. + */ + function set( $key, $value, $expiration = WP_FS__TIME_24_HOURS_IN_SEC, $created = WP_FS__SCRIPT_START_TIME ) { + $this->_logger->entrance( 'key = ' . $key ); + + $cache_entry = new stdClass(); + + $cache_entry->result = $value; + $cache_entry->created = $created; + $cache_entry->timestamp = $created + $expiration; + $this->_options->set_option( $key, $cache_entry, true ); + } + + /** + * Get cached record expiration, or false if not cached or expired. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.7.3 + * + * @param string $key + * + * @return bool|int + */ + function get_record_expiration( $key ) { + $this->_logger->entrance( 'key = ' . $key ); + + $cache_entry = $this->_options->get_option( $key, false ); + + if ( is_object( $cache_entry ) && + isset( $cache_entry->timestamp ) && + is_numeric( $cache_entry->timestamp ) && + $cache_entry->timestamp > WP_FS__SCRIPT_START_TIME + ) { + return $cache_entry->timestamp; + } + + return false; + } + + /** + * Purge cached item. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.6 + * + * @param string $key + */ + function purge( $key ) { + $this->_logger->entrance( 'key = ' . $key ); + + $this->_options->unset_option( $key, true ); + } + + /** + * Extend cached item caching period. + * + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + * + * @param string $key + * @param int $expiration + * + * @return bool + */ + function update_expiration( $key, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) { + $this->_logger->entrance( 'key = ' . $key ); + + $cache_entry = $this->_options->get_option( $key, false ); + + if ( ! is_object( $cache_entry ) || + ! isset( $cache_entry->timestamp ) || + ! is_numeric( $cache_entry->timestamp ) + ) { + return false; + } + + $this->set( $key, $cache_entry->result, $expiration, $cache_entry->created ); + + return true; + } + + /** + * Set cached item as expired. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.2.7 + * + * @param string $key + */ + function expire( $key ) { + $this->_logger->entrance( 'key = ' . $key ); + + $cache_entry = $this->_options->get_option( $key, false ); + + if ( is_object( $cache_entry ) && + isset( $cache_entry->timestamp ) && + is_numeric( $cache_entry->timestamp ) + ) { + // Set to expired. + $cache_entry->timestamp = WP_FS__SCRIPT_START_TIME; + $this->_options->set_option( $key, $cache_entry, true ); + } + } + + #-------------------------------------------------------------------------------- + #region Migration + #-------------------------------------------------------------------------------- + + /** + * Migrate options from site level. + * + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + */ + function migrate_to_network() { + $this->_options->migrate_to_network(); + } + + #endregion }\ No newline at end of file
Vulnerability Existed: no No vulnerabilities detected. Explanation: The provided diff shows only formatting changes (line ending conversions from Unix LF to DOS CRLF or similar whitespace normalization). There are no functional code changes, logic modifications, or security-related alterations in this diff. All the actual code implementation remains identical between versions 1.2.11 and 1.2.12. The file `class-fs-cache-manager.php` implements a caching manager with standard WordPress option storage patterns. The code includes proper type checking (`is_object()`, `is_numeric()`), timestamp validation, and expiration checking. Since there are no code changes in this update, there are no security fixes to analyze.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/managers/class-fs-gdpr-manager.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/managers/class-fs-gdpr-manager.php 2026-01-19 00:17:37.659045528 +0000@@ -1,190 +1,190 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.1.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_GDPR_Manager {- /**- * @var FS_Option_Manager- */- private $_storage;- /**- * @var array {- * @type bool $required Are GDPR rules apply on the current context admin.- * @type bool $show_opt_in_notice Should the marketing and offers opt-in message be shown to the admin or not. If not set, defaults to `true`.- * @type int $notice_shown_at Last time the special GDPR opt-in message was shown to the current admin.- * }- */- private $_data;- /**- * @var int- */- private $_wp_user_id;- /**- * @var string- */- private $_option_name;- /**- * @var FS_Admin_Notices- */- private $_notices;-- #--------------------------------------------------------------------------------- #region Singleton- #---------------------------------------------------------------------------------- /**- * @var FS_GDPR_Manager- */- private static $_instance;-- /**- * @return FS_GDPR_Manager- */- public static function instance() {- if ( ! isset( self::$_instance ) ) {- self::$_instance = new self();- }-- return self::$_instance;- }-- #endregion-- private function __construct() {- $this->_storage = FS_Option_Manager::get_manager( WP_FS__GDPR_OPTION_NAME, true, true );- $this->_wp_user_id = Freemius::get_current_wp_user_id();- $this->_option_name = "u{$this->_wp_user_id}";- $this->_data = $this->_storage->get_option( $this->_option_name, array() );- $this->_notices = FS_Admin_Notices::instance( 'all_admins', '', '', true );-- if ( ! is_array( $this->_data ) ) {- $this->_data = array();- }- }-- /**- * Update a GDPR option for the current admin and store it.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @param string $name- * @param mixed $value- */- private function update_option( $name, $value ) {- $this->_data[ $name ] = $value;-- $this->_storage->set_option( $this->_option_name, $this->_data, true );- }-- /**- * @author Leo Fajardo (@leorw)- * @since 2.1.0- *- * @param bool $is_required- */- public function store_is_required( $is_required ) {- $this->update_option( 'required', $is_required );- }-- /**- * Checks if the GDPR opt-in sticky notice is currently shown.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @return bool- */- public function is_opt_in_notice_shown() {- return $this->_notices->has_sticky( "gdpr_optin_actions_{$this->_wp_user_id}", true );- }-- /**- * Remove the GDPR opt-in sticky notice.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- */- public function remove_opt_in_notice() {- $this->_notices->remove_sticky( "gdpr_optin_actions_{$this->_wp_user_id}", true );-- $this->disable_opt_in_notice();- }-- /**- * Prevents the opt-in message from being added/shown.- *- * @author Leo Fajardo (@leorw)- * @since 2.1.0- */- public function disable_opt_in_notice() {- $this->update_option( 'show_opt_in_notice', false );- }-- /**- * Checks if a GDPR opt-in message needs to be shown to the current admin.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @return bool- */- public function should_show_opt_in_notice() {- return (- ! isset( $this->_data['show_opt_in_notice'] ) ||- true === $this->_data['show_opt_in_notice']- );- }-- /**- * Get the last time the GDPR opt-in notice was shown.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- *- * @return false|int- */- public function last_time_notice_was_shown() {- return isset( $this->_data['notice_shown_at'] ) ?- $this->_data['notice_shown_at'] :- false;- }-- /**- * Update the timestamp of the last time the GDPR opt-in message was shown to now.- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- */- public function notice_was_just_shown() {- $this->update_option( 'notice_shown_at', WP_FS__SCRIPT_START_TIME );- }-- /**- * @param string $message- * @param string|null $plugin_title- *- * @author Vova Feldman (@svovaf)- * @since 2.1.0- */- public function add_opt_in_sticky_notice( $message, $plugin_title = null ) {- $this->_notices->add_sticky(- $message,- "gdpr_optin_actions_{$this->_wp_user_id}",- '',- 'promotion',- true,- $this->_wp_user_id,- $plugin_title,- true- );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.1.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_GDPR_Manager { + /** + * @var FS_Option_Manager + */ + private $_storage; + /** + * @var array { + * @type bool $required Are GDPR rules apply on the current context admin. + * @type bool $show_opt_in_notice Should the marketing and offers opt-in message be shown to the admin or not. If not set, defaults to `true`. + * @type int $notice_shown_at Last time the special GDPR opt-in message was shown to the current admin. + * } + */ + private $_data; + /** + * @var int + */ + private $_wp_user_id; + /** + * @var string + */ + private $_option_name; + /** + * @var FS_Admin_Notices + */ + private $_notices; + + #-------------------------------------------------------------------------------- + #region Singleton + #-------------------------------------------------------------------------------- + + /** + * @var FS_GDPR_Manager + */ + private static $_instance; + + /** + * @return FS_GDPR_Manager + */ + public static function instance() { + if ( ! isset( self::$_instance ) ) { + self::$_instance = new self(); + } + + return self::$_instance; + } + + #endregion + + private function __construct() { + $this->_storage = FS_Option_Manager::get_manager( WP_FS__GDPR_OPTION_NAME, true, true ); + $this->_wp_user_id = Freemius::get_current_wp_user_id(); + $this->_option_name = "u{$this->_wp_user_id}"; + $this->_data = $this->_storage->get_option( $this->_option_name, array() ); + $this->_notices = FS_Admin_Notices::instance( 'all_admins', '', '', true ); + + if ( ! is_array( $this->_data ) ) { + $this->_data = array(); + } + } + + /** + * Update a GDPR option for the current admin and store it. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @param string $name + * @param mixed $value + */ + private function update_option( $name, $value ) { + $this->_data[ $name ] = $value; + + $this->_storage->set_option( $this->_option_name, $this->_data, true ); + } + + /** + * @author Leo Fajardo (@leorw) + * @since 2.1.0 + * + * @param bool $is_required + */ + public function store_is_required( $is_required ) { + $this->update_option( 'required', $is_required ); + } + + /** + * Checks if the GDPR opt-in sticky notice is currently shown. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @return bool + */ + public function is_opt_in_notice_shown() { + return $this->_notices->has_sticky( "gdpr_optin_actions_{$this->_wp_user_id}", true ); + } + + /** + * Remove the GDPR opt-in sticky notice. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + */ + public function remove_opt_in_notice() { + $this->_notices->remove_sticky( "gdpr_optin_actions_{$this->_wp_user_id}", true ); + + $this->disable_opt_in_notice(); + } + + /** + * Prevents the opt-in message from being added/shown. + * + * @author Leo Fajardo (@leorw) + * @since 2.1.0 + */ + public function disable_opt_in_notice() { + $this->update_option( 'show_opt_in_notice', false ); + } + + /** + * Checks if a GDPR opt-in message needs to be shown to the current admin. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @return bool + */ + public function should_show_opt_in_notice() { + return ( + ! isset( $this->_data['show_opt_in_notice'] ) || + true === $this->_data['show_opt_in_notice'] + ); + } + + /** + * Get the last time the GDPR opt-in notice was shown. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + * + * @return false|int + */ + public function last_time_notice_was_shown() { + return isset( $this->_data['notice_shown_at'] ) ? + $this->_data['notice_shown_at'] : + false; + } + + /** + * Update the timestamp of the last time the GDPR opt-in message was shown to now. + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + */ + public function notice_was_just_shown() { + $this->update_option( 'notice_shown_at', WP_FS__SCRIPT_START_TIME ); + } + + /** + * @param string $message + * @param string|null $plugin_title + * + * @author Vova Feldman (@svovaf) + * @since 2.1.0 + */ + public function add_opt_in_sticky_notice( $message, $plugin_title = null ) { + $this->_notices->add_sticky( + $message, + "gdpr_optin_actions_{$this->_wp_user_id}", + '', + 'promotion', + true, + $this->_wp_user_id, + $plugin_title, + true + ); + } }\ No newline at end of file
**Analysis Result:** Vulnerability Existed: no No Security Vulnerabilities Detected Explanation: The provided diff shows only a line-ending change (CRLF to LF conversion) across the entire file. The actual code content remains identical between versions 1.2.11 and 1.2.12. No code logic has been modified, no new code has been introduced, and no existing code has been removed. Therefore, no security fixes or security regressions are present in this diff. This is a formatting-only change that normalizes line endings to Unix-style (LF).
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/managers/class-fs-key-value-storage.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/managers/class-fs-key-value-storage.php 2026-01-19 00:17:37.659045528 +0000@@ -1,402 +1,402 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.7- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Class FS_Key_Value_Storage- *- * @property int $install_timestamp- * @property int $activation_timestamp- * @property int $sync_timestamp- * @property object $sync_cron- * @property int $install_sync_timestamp- * @property array $connectivity_test- * @property array $is_on- * @property object $trial_plan- * @property bool $has_trial_plan- * @property bool $trial_promotion_shown- * @property string $sdk_version- * @property string $sdk_last_version- * @property bool $sdk_upgrade_mode- * @property bool $sdk_downgrade_mode- * @property bool $plugin_upgrade_mode- * @property bool $plugin_downgrade_mode- * @property string $plugin_version- * @property string $plugin_last_version- * @property bool $is_plugin_new_install- * @property bool $was_plugin_loaded- * @property object $plugin_main_file- * @property bool $prev_is_premium- * @property array $is_anonymous- * @property bool $is_pending_activation- * @property bool $sticky_optin_added- * @property object $uninstall_reason- * @property object $subscription- */- class FS_Key_Value_Storage implements ArrayAccess, Iterator, Countable {- /**- * @var string- */- protected $_id;-- /**- * @since 1.2.2- *- * @var string- */- protected $_secondary_id;-- /**- * @since 2.0.0- * @var int The ID of the blog that is associated with the current site level options.- */- private $_blog_id = 0;-- /**- * @since 2.0.0- * @var bool- */- private $_is_multisite_storage;-- /**- * @var array- */- protected $_data;-- /**- * @var FS_Key_Value_Storage[]- */- private static $_instances = array();-- /**- * @var FS_Logger- */- protected $_logger;-- /**- * @param string $id- * @param string $secondary_id- * @param bool $network_level_or_blog_id- *- * @return FS_Key_Value_Storage- */- static function instance( $id, $secondary_id, $network_level_or_blog_id = false ) {- $key = $id . ':' . $secondary_id;-- if ( is_multisite() ) {- if ( true === $network_level_or_blog_id ) {- $key .= ':ms';- } else if ( is_numeric( $network_level_or_blog_id ) && $network_level_or_blog_id > 0 ) {- $key .= ":{$network_level_or_blog_id}";- } else {- $network_level_or_blog_id = get_current_blog_id();-- $key .= ":{$network_level_or_blog_id}";- }- }-- if ( ! isset( self::$_instances[ $key ] ) ) {- self::$_instances[ $key ] = new FS_Key_Value_Storage( $id, $secondary_id, $network_level_or_blog_id );- }-- return self::$_instances[ $key ];- }-- protected function __construct( $id, $secondary_id, $network_level_or_blog_id = false ) {- $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $secondary_id . '_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );-- $this->_id = $id;- $this->_secondary_id = $secondary_id;-- if ( is_multisite() ) {- $this->_is_multisite_storage = ( true === $network_level_or_blog_id );-- if ( is_numeric( $network_level_or_blog_id ) ) {- $this->_blog_id = $network_level_or_blog_id;- }- } else {- $this->_is_multisite_storage = false;- }-- $this->load();- }-- protected function get_option_manager() {- return FS_Option_Manager::get_manager(- WP_FS__ACCOUNTS_OPTION_NAME,- true,- $this->_is_multisite_storage ?- true :- ( $this->_blog_id > 0 ? $this->_blog_id : false )- );- }-- protected function get_all_data() {- return $this->get_option_manager()->get_option( $this->_id, array() );- }-- /**- * Load plugin data from local DB.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.7- */- function load() {- $all_plugins_data = $this->get_all_data();- $this->_data = isset( $all_plugins_data[ $this->_secondary_id ] ) ?- $all_plugins_data[ $this->_secondary_id ] :- array();- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @param string $key- * @param mixed $value- * @param bool $flush- */- function store( $key, $value, $flush = true ) {- if ( $this->_logger->is_on() ) {- $this->_logger->entrance( $key . ' = ' . var_export( $value, true ) );- }-- if ( array_key_exists( $key, $this->_data ) && $value === $this->_data[ $key ] ) {- // No need to store data if the value wasn't changed.- return;- }-- $all_data = $this->get_all_data();-- $this->_data[ $key ] = $value;-- $all_data[ $this->_secondary_id ] = $this->_data;-- $options_manager = $this->get_option_manager();- $options_manager->set_option( $this->_id, $all_data, $flush );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 2.0.0- */- function save() {- $this->get_option_manager()->store();- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @param bool $store- * @param string[] $exceptions Set of keys to keep and not clear.- */- function clear_all( $store = true, $exceptions = array() ) {- $new_data = array();- foreach ( $exceptions as $key ) {- if ( isset( $this->_data[ $key ] ) ) {- $new_data[ $key ] = $this->_data[ $key ];- }- }-- $this->_data = $new_data;-- if ( $store ) {- $all_data = $this->get_all_data();- $all_data[ $this->_secondary_id ] = $this->_data;- $options_manager = $this->get_option_manager();- $options_manager->set_option( $this->_id, $all_data, true );- }- }-- /**- * Delete key-value storage.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- */- function delete() {- $this->_data = array();-- $all_data = $this->get_all_data();- unset( $all_data[ $this->_secondary_id ] );- $options_manager = $this->get_option_manager();- $options_manager->set_option( $this->_id, $all_data, true );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @param string $key- * @param bool $store- */- function remove( $key, $store = true ) {- if ( ! array_key_exists( $key, $this->_data ) ) {- return;- }-- unset( $this->_data[ $key ] );-- if ( $store ) {- $all_data = $this->get_all_data();- $all_data[ $this->_secondary_id ] = $this->_data;- $options_manager = $this->get_option_manager();- $options_manager->set_option( $this->_id, $all_data, true );- }- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @param string $key- * @param mixed $default- *- * @return bool|\FS_Plugin- */- function get( $key, $default = false ) {- return array_key_exists( $key, $this->_data ) ?- $this->_data[ $key ] :- $default;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 2.0.0- *- * @return string- */- function get_secondary_id() {- return $this->_secondary_id;- }--- /* ArrayAccess + Magic Access (better for refactoring)- -----------------------------------------------------------------------------------*/- function __set( $k, $v ) {- $this->store( $k, $v );- }-- function __isset( $k ) {- return array_key_exists( $k, $this->_data );- }-- function __unset( $k ) {- $this->remove( $k );- }-- function __get( $k ) {- return $this->get( $k, null );- }-- #[ReturnTypeWillChange]- function offsetSet( $k, $v ) {- if ( is_null( $k ) ) {- throw new Exception( 'Can\'t append value to request params.' );- } else {- $this->{$k} = $v;- }- }-- #[ReturnTypeWillChange]- function offsetExists( $k ) {- return array_key_exists( $k, $this->_data );- }-- #[ReturnTypeWillChange]- function offsetUnset( $k ) {- unset( $this->$k );- }-- #[ReturnTypeWillChange]- function offsetGet( $k ) {- return $this->get( $k, null );- }-- /**- * (PHP 5 >= 5.0.0)<br/>- * Return the current element- *- * @link http://php.net/manual/en/iterator.current.php- * @return mixed Can return any type.- */- #[ReturnTypeWillChange]- public function current() {- return current( $this->_data );- }-- /**- * (PHP 5 >= 5.0.0)<br/>- * Move forward to next element- *- * @link http://php.net/manual/en/iterator.next.php- * @return void Any returned value is ignored.- */- #[ReturnTypeWillChange]- public function next() {- next( $this->_data );- }-- /**- * (PHP 5 >= 5.0.0)<br/>- * Return the key of the current element- *- * @link http://php.net/manual/en/iterator.key.php- * @return mixed scalar on success, or null on failure.- */- #[ReturnTypeWillChange]- public function key() {- return key( $this->_data );- }-- /**- * (PHP 5 >= 5.0.0)<br/>- * Checks if current position is valid- *- * @link http://php.net/manual/en/iterator.valid.php- * @return boolean The return value will be casted to boolean and then evaluated.- * Returns true on success or false on failure.- */- #[ReturnTypeWillChange]- public function valid() {- $key = key( $this->_data );-- return ( $key !== null && $key !== false );- }-- /**- * (PHP 5 >= 5.0.0)<br/>- * Rewind the Iterator to the first element- *- * @link http://php.net/manual/en/iterator.rewind.php- * @return void Any returned value is ignored.- */- #[ReturnTypeWillChange]- public function rewind() {- reset( $this->_data );- }-- /**- * (PHP 5 >= 5.1.0)<br/>- * Count elements of an object- *- * @link http://php.net/manual/en/countable.count.php- * @return int The custom count as an integer.- * </p>- * <p>- * The return value is cast to an integer.- */- #[ReturnTypeWillChange]- public function count() {- return count( $this->_data );- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.7 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Class FS_Key_Value_Storage + * + * @property int $install_timestamp + * @property int $activation_timestamp + * @property int $sync_timestamp + * @property object $sync_cron + * @property int $install_sync_timestamp + * @property array $connectivity_test + * @property array $is_on + * @property object $trial_plan + * @property bool $has_trial_plan + * @property bool $trial_promotion_shown + * @property string $sdk_version + * @property string $sdk_last_version + * @property bool $sdk_upgrade_mode + * @property bool $sdk_downgrade_mode + * @property bool $plugin_upgrade_mode + * @property bool $plugin_downgrade_mode + * @property string $plugin_version + * @property string $plugin_last_version + * @property bool $is_plugin_new_install + * @property bool $was_plugin_loaded + * @property object $plugin_main_file + * @property bool $prev_is_premium + * @property array $is_anonymous + * @property bool $is_pending_activation + * @property bool $sticky_optin_added + * @property object $uninstall_reason + * @property object $subscription + */ + class FS_Key_Value_Storage implements ArrayAccess, Iterator, Countable { + /** + * @var string + */ + protected $_id; + + /** + * @since 1.2.2 + * + * @var string + */ + protected $_secondary_id; + + /** + * @since 2.0.0 + * @var int The ID of the blog that is associated with the current site level options. + */ + private $_blog_id = 0; + + /** + * @since 2.0.0 + * @var bool + */ + private $_is_multisite_storage; + + /** + * @var array + */ + protected $_data; + + /** + * @var FS_Key_Value_Storage[] + */ + private static $_instances = array(); + + /** + * @var FS_Logger + */ + protected $_logger; + + /** + * @param string $id + * @param string $secondary_id + * @param bool $network_level_or_blog_id + * + * @return FS_Key_Value_Storage + */ + static function instance( $id, $secondary_id, $network_level_or_blog_id = false ) { + $key = $id . ':' . $secondary_id; + + if ( is_multisite() ) { + if ( true === $network_level_or_blog_id ) { + $key .= ':ms'; + } else if ( is_numeric( $network_level_or_blog_id ) && $network_level_or_blog_id > 0 ) { + $key .= ":{$network_level_or_blog_id}"; + } else { + $network_level_or_blog_id = get_current_blog_id(); + + $key .= ":{$network_level_or_blog_id}"; + } + } + + if ( ! isset( self::$_instances[ $key ] ) ) { + self::$_instances[ $key ] = new FS_Key_Value_Storage( $id, $secondary_id, $network_level_or_blog_id ); + } + + return self::$_instances[ $key ]; + } + + protected function __construct( $id, $secondary_id, $network_level_or_blog_id = false ) { + $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $secondary_id . '_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK ); + + $this->_id = $id; + $this->_secondary_id = $secondary_id; + + if ( is_multisite() ) { + $this->_is_multisite_storage = ( true === $network_level_or_blog_id ); + + if ( is_numeric( $network_level_or_blog_id ) ) { + $this->_blog_id = $network_level_or_blog_id; + } + } else { + $this->_is_multisite_storage = false; + } + + $this->load(); + } + + protected function get_option_manager() { + return FS_Option_Manager::get_manager( + WP_FS__ACCOUNTS_OPTION_NAME, + true, + $this->_is_multisite_storage ? + true : + ( $this->_blog_id > 0 ? $this->_blog_id : false ) + ); + } + + protected function get_all_data() { + return $this->get_option_manager()->get_option( $this->_id, array() ); + } + + /** + * Load plugin data from local DB. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + */ + function load() { + $all_plugins_data = $this->get_all_data(); + $this->_data = isset( $all_plugins_data[ $this->_secondary_id ] ) ? + $all_plugins_data[ $this->_secondary_id ] : + array(); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @param string $key + * @param mixed $value + * @param bool $flush + */ + function store( $key, $value, $flush = true ) { + if ( $this->_logger->is_on() ) { + $this->_logger->entrance( $key . ' = ' . var_export( $value, true ) ); + } + + if ( array_key_exists( $key, $this->_data ) && $value === $this->_data[ $key ] ) { + // No need to store data if the value wasn't changed. + return; + } + + $all_data = $this->get_all_data(); + + $this->_data[ $key ] = $value; + + $all_data[ $this->_secondary_id ] = $this->_data; + + $options_manager = $this->get_option_manager(); + $options_manager->set_option( $this->_id, $all_data, $flush ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + */ + function save() { + $this->get_option_manager()->store(); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @param bool $store + * @param string[] $exceptions Set of keys to keep and not clear. + */ + function clear_all( $store = true, $exceptions = array() ) { + $new_data = array(); + foreach ( $exceptions as $key ) { + if ( isset( $this->_data[ $key ] ) ) { + $new_data[ $key ] = $this->_data[ $key ]; + } + } + + $this->_data = $new_data; + + if ( $store ) { + $all_data = $this->get_all_data(); + $all_data[ $this->_secondary_id ] = $this->_data; + $options_manager = $this->get_option_manager(); + $options_manager->set_option( $this->_id, $all_data, true ); + } + } + + /** + * Delete key-value storage. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + */ + function delete() { + $this->_data = array(); + + $all_data = $this->get_all_data(); + unset( $all_data[ $this->_secondary_id ] ); + $options_manager = $this->get_option_manager(); + $options_manager->set_option( $this->_id, $all_data, true ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @param string $key + * @param bool $store + */ + function remove( $key, $store = true ) { + if ( ! array_key_exists( $key, $this->_data ) ) { + return; + } + + unset( $this->_data[ $key ] ); + + if ( $store ) { + $all_data = $this->get_all_data(); + $all_data[ $this->_secondary_id ] = $this->_data; + $options_manager = $this->get_option_manager(); + $options_manager->set_option( $this->_id, $all_data, true ); + } + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @param string $key + * @param mixed $default + * + * @return bool|\FS_Plugin + */ + function get( $key, $default = false ) { + return array_key_exists( $key, $this->_data ) ? + $this->_data[ $key ] : + $default; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + * + * @return string + */ + function get_secondary_id() { + return $this->_secondary_id; + } + + + /* ArrayAccess + Magic Access (better for refactoring) + -----------------------------------------------------------------------------------*/ + function __set( $k, $v ) { + $this->store( $k, $v ); + } + + function __isset( $k ) { + return array_key_exists( $k, $this->_data ); + } + + function __unset( $k ) { + $this->remove( $k ); + } + + function __get( $k ) { + return $this->get( $k, null ); + } + + #[ReturnTypeWillChange] + function offsetSet( $k, $v ) { + if ( is_null( $k ) ) { + throw new Exception( 'Can\'t append value to request params.' ); + } else { + $this->{$k} = $v; + } + } + + #[ReturnTypeWillChange] + function offsetExists( $k ) { + return array_key_exists( $k, $this->_data ); + } + + #[ReturnTypeWillChange] + function offsetUnset( $k ) { + unset( $this->$k ); + } + + #[ReturnTypeWillChange] + function offsetGet( $k ) { + return $this->get( $k, null ); + } + + /** + * (PHP 5 >= 5.0.0)<br/> + * Return the current element + * + * @link http://php.net/manual/en/iterator.current.php + * @return mixed Can return any type. + */ + #[ReturnTypeWillChange] + public function current() { + return current( $this->_data ); + } + + /** + * (PHP 5 >= 5.0.0)<br/> + * Move forward to next element + * + * @link http://php.net/manual/en/iterator.next.php + * @return void Any returned value is ignored. + */ + #[ReturnTypeWillChange] + public function next() { + next( $this->_data ); + } + + /** + * (PHP 5 >= 5.0.0)<br/> + * Return the key of the current element + * + * @link http://php.net/manual/en/iterator.key.php + * @return mixed scalar on success, or null on failure. + */ + #[ReturnTypeWillChange] + public function key() { + return key( $this->_data ); + } + + /** + * (PHP 5 >= 5.0.0)<br/> + * Checks if current position is valid + * + * @link http://php.net/manual/en/iterator.valid.php + * @return boolean The return value will be casted to boolean and then evaluated. + * Returns true on success or false on failure. + */ + #[ReturnTypeWillChange] + public function valid() { + $key = key( $this->_data ); + + return ( $key !== null && $key !== false ); + } + + /** + * (PHP 5 >= 5.0.0)<br/> + * Rewind the Iterator to the first element + * + * @link http://php.net/manual/en/iterator.rewind.php + * @return void Any returned value is ignored. + */ + #[ReturnTypeWillChange] + public function rewind() { + reset( $this->_data ); + } + + /** + * (PHP 5 >= 5.1.0)<br/> + * Count elements of an object + * + * @link http://php.net/manual/en/countable.count.php + * @return int The custom count as an integer. + * </p> + * <p> + * The return value is cast to an integer. + */ + #[ReturnTypeWillChange] + public function count() { + return count( $this->_data ); + } }\ No newline at end of file
Vulnerability Existed: no Analysis: This diff shows a **formatting/whitespace change only** - the file content remains functionally identical between versions 1.2.11 and 1.2.12. The only modifications are: 1. Line ending changes (Unix/Linux line endings `\n` instead of Windows line endings `\r\n`) 2. Possible tab/space normalization in indentation **No security vulnerabilities are introduced or fixed** because: - All code logic remains unchanged - No new functions or methods are added - No existing security controls are modified - No input validation, sanitization, or authentication mechanisms are altered - No database queries or file operations are changed - The class structure, permissions, and data handling remain identical **Conclusion:** This is a routine code formatting/cleanup commit with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/managers/class-fs-license-manager.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/managers/class-fs-license-manager.php 2026-01-19 00:17:37.659045528 +0000@@ -1,104 +1,104 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.6- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_License_Manager /*extends FS_Abstract_Manager*/- {-//-//-// /**-// * @var FS_License_Manager[]-// */-// private static $_instances = array();-//-// static function instance( Freemius $fs ) {-// $slug = strtolower( $fs->get_slug() );-//-// if ( ! isset( self::$_instances[ $slug ] ) ) {-// self::$_instances[ $slug ] = new FS_License_Manager( $slug, $fs );-// }-//-// return self::$_instances[ $slug ];-// }-//-//// private function __construct($slug) {-//// parent::__construct($slug);-//// }-//-// function entry_id() {-// return 'licenses';-// }-//-// function sync( $id ) {-//-// }-//-// /**-// * @author Vova Feldman (@svovaf)-// * @since 1.0.5-// * @uses FS_Api-// *-// * @param number|bool $plugin_id-// *-// * @return FS_Plugin_License[]|stdClass Licenses or API error.-// */-// function api_get_user_plugin_licenses( $plugin_id = false ) {-// $api = $this->_fs->get_api_user_scope();-//-// if ( ! is_numeric( $plugin_id ) ) {-// $plugin_id = $this->_fs->get_id();-// }-//-// $result = $api->call( "/plugins/{$plugin_id}/licenses.json" );-//-// if ( ! isset( $result->error ) ) {-// for ( $i = 0, $len = count( $result->licenses ); $i < $len; $i ++ ) {-// $result->licenses[ $i ] = new FS_Plugin_License( $result->licenses[ $i ] );-// }-//-// $result = $result->licenses;-// }-//-// return $result;-// }-//-// function api_get_many() {-//-// }-//-// function api_activate( $id ) {-//-// }-//-// function api_deactivate( $id ) {-//-// }-- /**- * @param FS_Plugin_License[] $licenses- *- * @return bool- */- static function has_premium_license( $licenses ) {- if ( is_array( $licenses ) ) {- foreach ( $licenses as $license ) {- /**- * @var FS_Plugin_License $license- */- if ( ! $license->is_utilized() && $license->is_features_enabled() ) {- return true;- }- }- }-- return false;- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.6 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_License_Manager /*extends FS_Abstract_Manager*/ + { +// +// +// /** +// * @var FS_License_Manager[] +// */ +// private static $_instances = array(); +// +// static function instance( Freemius $fs ) { +// $slug = strtolower( $fs->get_slug() ); +// +// if ( ! isset( self::$_instances[ $slug ] ) ) { +// self::$_instances[ $slug ] = new FS_License_Manager( $slug, $fs ); +// } +// +// return self::$_instances[ $slug ]; +// } +// +//// private function __construct($slug) { +//// parent::__construct($slug); +//// } +// +// function entry_id() { +// return 'licenses'; +// } +// +// function sync( $id ) { +// +// } +// +// /** +// * @author Vova Feldman (@svovaf) +// * @since 1.0.5 +// * @uses FS_Api +// * +// * @param number|bool $plugin_id +// * +// * @return FS_Plugin_License[]|stdClass Licenses or API error. +// */ +// function api_get_user_plugin_licenses( $plugin_id = false ) { +// $api = $this->_fs->get_api_user_scope(); +// +// if ( ! is_numeric( $plugin_id ) ) { +// $plugin_id = $this->_fs->get_id(); +// } +// +// $result = $api->call( "/plugins/{$plugin_id}/licenses.json" ); +// +// if ( ! isset( $result->error ) ) { +// for ( $i = 0, $len = count( $result->licenses ); $i < $len; $i ++ ) { +// $result->licenses[ $i ] = new FS_Plugin_License( $result->licenses[ $i ] ); +// } +// +// $result = $result->licenses; +// } +// +// return $result; +// } +// +// function api_get_many() { +// +// } +// +// function api_activate( $id ) { +// +// } +// +// function api_deactivate( $id ) { +// +// } + + /** + * @param FS_Plugin_License[] $licenses + * + * @return bool + */ + static function has_premium_license( $licenses ) { + if ( is_array( $licenses ) ) { + foreach ( $licenses as $license ) { + /** + * @var FS_Plugin_License $license + */ + if ( ! $license->is_utilized() && $license->is_features_enabled() ) { + return true; + } + } + } + + return false; + } }\ No newline at end of file
Vulnerability Existed: no No Vulnerabilities Detected - inc/freemius/includes/managers/class-fs-license-manager.php Explanation: This diff contains only whitespace and line ending changes (conversion from CRLF to LF line endings). The actual code logic, structure, and functionality remain completely identical between versions 1.2.11 and 1.2.12. No code modifications, additions, or deletions have been made that could introduce or fix security vulnerabilities. The file contains only PHP class and method declarations with no executable code that processes user input, handles sensitive data, or performs security-critical operations in a way that would be affected by these formatting changes.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/managers/class-fs-option-manager.php 2026-01-19 00:16:00.449014940 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/managers/class-fs-option-manager.php 2026-01-19 00:17:37.659045528 +0000@@ -1,476 +1,476 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * 2-layer lazy options manager.- * layer 2: Memory- * layer 1: Database (options table). All options stored as one option record in the DB to reduce number of DB queries.- *- * If load() is not explicitly called, starts as empty manager. Same thing about saving the data - you have to explicitly call store().- *- * Class Freemius_Option_Manager- */- class FS_Option_Manager {- /**- * @var string- */- private $_id;- /**- * @var array|object- */- private $_options;- /**- * @var FS_Logger- */- private $_logger;-- /**- * @since 2.0.0- * @var int The ID of the blog that is associated with the current site level options.- */- private $_blog_id = 0;-- /**- * @since 2.0.0- * @var bool- */- private $_is_network_storage;-- /**- * @var bool|null- */- private $_autoload;-- /**- * @var array[string]FS_Option_Manager {- * @key string- * @value FS_Option_Manager- * }- */- private static $_MANAGERS = array();-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @param string $id- * @param bool $load- * @param bool|int $network_level_or_blog_id Since 2.0.0- * @param bool|null $autoload- */- private function __construct(- $id,- $load = false,- $network_level_or_blog_id = false,- $autoload = null- ) {- $id = strtolower( $id );-- $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_opt_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );-- $this->_logger->entrance();- $this->_logger->log( 'id = ' . $id );-- $this->_id = $id;-- $this->_autoload = $autoload;-- if ( is_multisite() ) {- $this->_is_network_storage = ( true === $network_level_or_blog_id );-- if ( is_numeric( $network_level_or_blog_id ) ) {- $this->_blog_id = $network_level_or_blog_id;- }- } else {- $this->_is_network_storage = false;- }-- if ( $load ) {- $this->load();- }- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @param string $id- * @param bool $load- * @param bool|int $network_level_or_blog_id Since 2.0.0- * @param bool|null $autoload- *- * @return \FS_Option_Manager- */- static function get_manager(- $id,- $load = false,- $network_level_or_blog_id = false,- $autoload = null- ) {- $key = strtolower( $id );-- if ( is_multisite() ) {- if ( true === $network_level_or_blog_id ) {- $key .= ':ms';- } else if ( is_numeric( $network_level_or_blog_id ) && $network_level_or_blog_id > 0 ) {- $key .= ":{$network_level_or_blog_id}";- } else {- $network_level_or_blog_id = get_current_blog_id();-- $key .= ":{$network_level_or_blog_id}";- }- }-- if ( ! isset( self::$_MANAGERS[ $key ] ) ) {- self::$_MANAGERS[ $key ] = new FS_Option_Manager(- $id,- $load,- $network_level_or_blog_id,- $autoload- );- } // If load required but not yet loaded, load.- else if ( $load && ! self::$_MANAGERS[ $key ]->is_loaded() ) {- self::$_MANAGERS[ $key ]->load();- }-- return self::$_MANAGERS[ $key ];- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @param bool $flush- */- function load( $flush = false ) {- $this->_logger->entrance();-- if ( ! $flush && isset( $this->_options ) ) {- return;- }-- if ( isset( $this->_options ) ) {- // Clear prev options.- $this->clear();- }-- $option_name = $this->get_option_manager_name();-- if ( $this->_is_network_storage ) {- $this->_options = get_site_option( $option_name );- } else if ( $this->_blog_id > 0 ) {- $this->_options = get_blog_option( $this->_blog_id, $option_name );- } else {- $this->_options = get_option( $option_name );- }-- if ( is_string( $this->_options ) ) {- $this->_options = json_decode( $this->_options );- }--// $this->_logger->info('get_option = ' . var_export($this->_options, true));-- if ( false === $this->_options ) {- $this->clear();- }- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @return bool- */- function is_loaded() {- return isset( $this->_options );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @return bool- */- function is_empty() {- return ( $this->is_loaded() && false === $this->_options );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.6- *- * @param bool $flush- */- function clear( $flush = false ) {- $this->_logger->entrance();-- $this->_options = array();-- if ( $flush ) {- $this->store();- }- }-- /**- * Delete options manager from DB.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- */- function delete() {- $option_name = $this->get_option_manager_name();-- if ( $this->_is_network_storage ) {- delete_site_option( $option_name );- } else if ( $this->_blog_id > 0 ) {- delete_blog_option( $this->_blog_id, $option_name );- } else {- delete_option( $option_name );- }- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.6- *- * @param string $option- * @param bool $flush- *- * @return bool- */- function has_option( $option, $flush = false ) {- if ( ! $this->is_loaded() || $flush ) {- $this->load( $flush );- }-- return array_key_exists( $option, $this->_options );- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @param string $option- * @param mixed $default- * @param bool $flush- *- * @return mixed- */- function get_option( $option, $default = null, $flush = false ) {- $this->_logger->entrance( 'option = ' . $option );-- if ( ! $this->is_loaded() || $flush ) {- $this->load( $flush );- }-- if ( is_array( $this->_options ) ) {- $value = isset( $this->_options[ $option ] ) ?- $this->_options[ $option ] :- $default;- } else if ( is_object( $this->_options ) ) {- $value = isset( $this->_options->{$option} ) ?- $this->_options->{$option} :- $default;- } else {- $value = $default;- }-- /**- * If it's an object, return a clone of the object, otherwise,- * external changes of the object will actually change the value- * of the object in the option manager which may lead to an unexpected- * behaviour and data integrity when a store() call is triggered.- *- * Example:- * $object1 = $options->get_option( 'object1' );- * $object1->x = 123;- *- * $object2 = $options->get_option( 'object2' );- * $object2->y = 'dummy';- *- * $options->set_option( 'object2', $object2, true );- *- * If we don't return a clone of option 'object1', setting 'object2'- * will also store the updated value of 'object1' which is quite not- * an expected behaviour.- *- * @author Vova Feldman- */- return is_object( $value ) ? clone $value : $value;- }-- /**- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @param string $option- * @param mixed $value- * @param bool $flush- */- function set_option( $option, $value, $flush = false ) {- $this->_logger->entrance( 'option = ' . $option );-- if ( ! $this->is_loaded() ) {- $this->clear();- }-- /**- * If it's an object, store a clone of the object, otherwise,- * external changes of the object will actually change the value- * of the object in the options manager which may lead to an unexpected- * behaviour and data integrity when a store() call is triggered.- *- * Example:- * $object1 = new stdClass();- * $object1->x = 123;- *- * $options->set_option( 'object1', $object1 );- *- * $object1->x = 456;- *- * $options->set_option( 'object2', $object2, true );- *- * If we don't set the option as a clone of option 'object1', setting 'object2'- * will also store the updated value of 'object1' ($object1->x = 456 instead of- * $object1->x = 123) which is quite not an expected behaviour.- *- * @author Vova Feldman- */- $copy = is_object( $value ) ? clone $value : $value;-- if ( is_array( $this->_options ) ) {- $this->_options[ $option ] = $copy;- } else if ( is_object( $this->_options ) ) {- $this->_options->{$option} = $copy;- }-- if ( $flush ) {- $this->store();- }- }-- /**- * Unset option.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @param string $option- * @param bool $flush- */- function unset_option( $option, $flush = false ) {- $this->_logger->entrance( 'option = ' . $option );-- if ( is_array( $this->_options ) ) {- if ( ! isset( $this->_options[ $option ] ) ) {- return;- }-- unset( $this->_options[ $option ] );-- } else if ( is_object( $this->_options ) ) {- if ( ! isset( $this->_options->{$option} ) ) {- return;- }-- unset( $this->_options->{$option} );- }-- if ( $flush ) {- $this->store();- }- }-- /**- * Dump options to database.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.3- */- function store() {- $this->_logger->entrance();-- $option_name = $this->get_option_manager_name();-- if ( $this->_logger->is_on() ) {- $this->_logger->info( $option_name . ' = ' . var_export( $this->_options, true ) );- }-- // Update DB.- if ( $this->_is_network_storage ) {- update_site_option( $option_name, $this->_options );- } else if ( $this->_blog_id > 0 ) {- update_blog_option( $this->_blog_id, $option_name, $this->_options );- } else {- update_option( $option_name, $this->_options, $this->_autoload );- }- }-- /**- * Get options keys.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.3- *- * @return string[]- */- function get_options_keys() {- if ( is_array( $this->_options ) ) {- return array_keys( $this->_options );- } else if ( is_object( $this->_options ) ) {- return array_keys( get_object_vars( $this->_options ) );- }-- return array();- }-- #--------------------------------------------------------------------------------- #region Migration- #---------------------------------------------------------------------------------- /**- * Migrate options from site level.- *- * @author Vova Feldman (@svovaf)- * @since 2.0.0- */- function migrate_to_network() {- $site_options = FS_Option_Manager::get_manager($this->_id, true, false);-- $options = is_object( $site_options->_options ) ?- get_object_vars( $site_options->_options ) :- $site_options->_options;-- if ( ! empty( $options ) ) {- foreach ( $options as $key => $val ) {- $this->set_option( $key, $val, false );- }-- $this->store();- }- }-- #endregion-- #--------------------------------------------------------------------------------- #region Helper Methods- #---------------------------------------------------------------------------------- /**- * @return string- */- private function get_option_manager_name() {- return $this->_id;- }-- #endregion- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * 2-layer lazy options manager. + * layer 2: Memory + * layer 1: Database (options table). All options stored as one option record in the DB to reduce number of DB queries. + * + * If load() is not explicitly called, starts as empty manager. Same thing about saving the data - you have to explicitly call store(). + * + * Class Freemius_Option_Manager + */ + class FS_Option_Manager { + /** + * @var string + */ + private $_id; + /** + * @var array|object + */ + private $_options; + /** + * @var FS_Logger + */ + private $_logger; + + /** + * @since 2.0.0 + * @var int The ID of the blog that is associated with the current site level options. + */ + private $_blog_id = 0; + + /** + * @since 2.0.0 + * @var bool + */ + private $_is_network_storage; + + /** + * @var bool|null + */ + private $_autoload; + + /** + * @var array[string]FS_Option_Manager { + * @key string + * @value FS_Option_Manager + * } + */ + private static $_MANAGERS = array(); + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @param string $id + * @param bool $load + * @param bool|int $network_level_or_blog_id Since 2.0.0 + * @param bool|null $autoload + */ + private function __construct( + $id, + $load = false, + $network_level_or_blog_id = false, + $autoload = null + ) { + $id = strtolower( $id ); + + $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_opt_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK ); + + $this->_logger->entrance(); + $this->_logger->log( 'id = ' . $id ); + + $this->_id = $id; + + $this->_autoload = $autoload; + + if ( is_multisite() ) { + $this->_is_network_storage = ( true === $network_level_or_blog_id ); + + if ( is_numeric( $network_level_or_blog_id ) ) { + $this->_blog_id = $network_level_or_blog_id; + } + } else { + $this->_is_network_storage = false; + } + + if ( $load ) { + $this->load(); + } + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @param string $id + * @param bool $load + * @param bool|int $network_level_or_blog_id Since 2.0.0 + * @param bool|null $autoload + * + * @return \FS_Option_Manager + */ + static function get_manager( + $id, + $load = false, + $network_level_or_blog_id = false, + $autoload = null + ) { + $key = strtolower( $id ); + + if ( is_multisite() ) { + if ( true === $network_level_or_blog_id ) { + $key .= ':ms'; + } else if ( is_numeric( $network_level_or_blog_id ) && $network_level_or_blog_id > 0 ) { + $key .= ":{$network_level_or_blog_id}"; + } else { + $network_level_or_blog_id = get_current_blog_id(); + + $key .= ":{$network_level_or_blog_id}"; + } + } + + if ( ! isset( self::$_MANAGERS[ $key ] ) ) { + self::$_MANAGERS[ $key ] = new FS_Option_Manager( + $id, + $load, + $network_level_or_blog_id, + $autoload + ); + } // If load required but not yet loaded, load. + else if ( $load && ! self::$_MANAGERS[ $key ]->is_loaded() ) { + self::$_MANAGERS[ $key ]->load(); + } + + return self::$_MANAGERS[ $key ]; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @param bool $flush + */ + function load( $flush = false ) { + $this->_logger->entrance(); + + if ( ! $flush && isset( $this->_options ) ) { + return; + } + + if ( isset( $this->_options ) ) { + // Clear prev options. + $this->clear(); + } + + $option_name = $this->get_option_manager_name(); + + if ( $this->_is_network_storage ) { + $this->_options = get_site_option( $option_name ); + } else if ( $this->_blog_id > 0 ) { + $this->_options = get_blog_option( $this->_blog_id, $option_name ); + } else { + $this->_options = get_option( $option_name ); + } + + if ( is_string( $this->_options ) ) { + $this->_options = json_decode( $this->_options ); + } + +// $this->_logger->info('get_option = ' . var_export($this->_options, true)); + + if ( false === $this->_options ) { + $this->clear(); + } + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @return bool + */ + function is_loaded() { + return isset( $this->_options ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @return bool + */ + function is_empty() { + return ( $this->is_loaded() && false === $this->_options ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.6 + * + * @param bool $flush + */ + function clear( $flush = false ) { + $this->_logger->entrance(); + + $this->_options = array(); + + if ( $flush ) { + $this->store(); + } + } + + /** + * Delete options manager from DB. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + */ + function delete() { + $option_name = $this->get_option_manager_name(); + + if ( $this->_is_network_storage ) { + delete_site_option( $option_name ); + } else if ( $this->_blog_id > 0 ) { + delete_blog_option( $this->_blog_id, $option_name ); + } else { + delete_option( $option_name ); + } + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.6 + * + * @param string $option + * @param bool $flush + * + * @return bool + */ + function has_option( $option, $flush = false ) { + if ( ! $this->is_loaded() || $flush ) { + $this->load( $flush ); + } + + return array_key_exists( $option, $this->_options ); + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @param string $option + * @param mixed $default + * @param bool $flush + * + * @return mixed + */ + function get_option( $option, $default = null, $flush = false ) { + $this->_logger->entrance( 'option = ' . $option ); + + if ( ! $this->is_loaded() || $flush ) { + $this->load( $flush ); + } + + if ( is_array( $this->_options ) ) { + $value = isset( $this->_options[ $option ] ) ? + $this->_options[ $option ] : + $default; + } else if ( is_object( $this->_options ) ) { + $value = isset( $this->_options->{$option} ) ? + $this->_options->{$option} : + $default; + } else { + $value = $default; + } + + /** + * If it's an object, return a clone of the object, otherwise, + * external changes of the object will actually change the value + * of the object in the option manager which may lead to an unexpected + * behaviour and data integrity when a store() call is triggered. + * + * Example: + * $object1 = $options->get_option( 'object1' ); + * $object1->x = 123; + * + * $object2 = $options->get_option( 'object2' ); + * $object2->y = 'dummy'; + * + * $options->set_option( 'object2', $object2, true ); + * + * If we don't return a clone of option 'object1', setting 'object2' + * will also store the updated value of 'object1' which is quite not + * an expected behaviour. + * + * @author Vova Feldman + */ + return is_object( $value ) ? clone $value : $value; + } + + /** + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @param string $option + * @param mixed $value + * @param bool $flush + */ + function set_option( $option, $value, $flush = false ) { + $this->_logger->entrance( 'option = ' . $option ); + + if ( ! $this->is_loaded() ) { + $this->clear(); + } + + /** + * If it's an object, store a clone of the object, otherwise, + * external changes of the object will actually change the value + * of the object in the options manager which may lead to an unexpected + * behaviour and data integrity when a store() call is triggered. + * + * Example: + * $object1 = new stdClass(); + * $object1->x = 123; + * + * $options->set_option( 'object1', $object1 ); + * + * $object1->x = 456; + * + * $options->set_option( 'object2', $object2, true ); + * + * If we don't set the option as a clone of option 'object1', setting 'object2' + * will also store the updated value of 'object1' ($object1->x = 456 instead of + * $object1->x = 123) which is quite not an expected behaviour. + * + * @author Vova Feldman + */ + $copy = is_object( $value ) ? clone $value : $value; + + if ( is_array( $this->_options ) ) { + $this->_options[ $option ] = $copy; + } else if ( is_object( $this->_options ) ) { + $this->_options->{$option} = $copy; + } + + if ( $flush ) { + $this->store(); + } + } + + /** + * Unset option. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @param string $option + * @param bool $flush + */ + function unset_option( $option, $flush = false ) { + $this->_logger->entrance( 'option = ' . $option ); + + if ( is_array( $this->_options ) ) { + if ( ! isset( $this->_options[ $option ] ) ) { + return; + } + + unset( $this->_options[ $option ] ); + + } else if ( is_object( $this->_options ) ) { + if ( ! isset( $this->_options->{$option} ) ) { + return; + } + + unset( $this->_options->{$option} ); + } + + if ( $flush ) { + $this->store(); + } + } + + /** + * Dump options to database. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + */ + function store() { + $this->_logger->entrance(); + + $option_name = $this->get_option_manager_name(); + + if ( $this->_logger->is_on() ) { + $this->_logger->info( $option_name . ' = ' . var_export( $this->_options, true ) ); + } + + // Update DB. + if ( $this->_is_network_storage ) { + update_site_option( $option_name, $this->_options ); + } else if ( $this->_blog_id > 0 ) { + update_blog_option( $this->_blog_id, $option_name, $this->_options ); + } else { + update_option( $option_name, $this->_options, $this->_autoload ); + } + } + + /** + * Get options keys. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.3 + * + * @return string[] + */ + function get_options_keys() { + if ( is_array( $this->_options ) ) { + return array_keys( $this->_options ); + } else if ( is_object( $this->_options ) ) { + return array_keys( get_object_vars( $this->_options ) ); + } + + return array(); + } + + #-------------------------------------------------------------------------------- + #region Migration + #-------------------------------------------------------------------------------- + + /** + * Migrate options from site level. + * + * @author Vova Feldman (@svovaf) + * @since 2.0.0 + */ + function migrate_to_network() { + $site_options = FS_Option_Manager::get_manager($this->_id, true, false); + + $options = is_object( $site_options->_options ) ? + get_object_vars( $site_options->_options ) : + $site_options->_options; + + if ( ! empty( $options ) ) { + foreach ( $options as $key => $val ) { + $this->set_option( $key, $val, false ); + } + + $this->store(); + } + } + + #endregion + + #-------------------------------------------------------------------------------- + #region Helper Methods + #-------------------------------------------------------------------------------- + + /** + * @return string + */ + private function get_option_manager_name() { + return $this->_id; + } + + #endregion + }
# Security Analysis Report **File:** inc/freemius/includes/managers/class-fs-option-manager.php **Analysis Result:** Vulnerability Existed: **no** **Explanation:** This diff shows only **whitespace/line ending changes** (LF vs CRLF conversion or similar formatting). The actual code content remains identical between versions 1.2.11 and 1.2.12. No functional code modifications were made, and therefore no security vulnerabilities were introduced or fixed. The file continues to: - Properly use WordPress sanitization functions (`get_site_option`, `get_blog_option`, `get_option`) - Implement object cloning to prevent unintended reference mutations - Handle multisite contexts appropriately - Use WordPress native functions for option management **Conclusion:** This is a cosmetic update with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/managers/class-fs-plan-manager.php 2026-01-19 00:16:00.453015188 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/managers/class-fs-plan-manager.php 2026-01-19 00:17:37.659045528 +0000@@ -1,193 +1,193 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.6- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- class FS_Plan_Manager {- /**- * @var FS_Plan_Manager- */- private static $_instance;-- /**- * @return FS_Plan_Manager- */- static function instance() {- if ( ! isset( self::$_instance ) ) {- self::$_instance = new FS_Plan_Manager();- }-- return self::$_instance;- }-- private function __construct() {- }-- /**- * @param FS_Plugin_License[] $licenses- *- * @return bool- */- function has_premium_license( $licenses ) {- if ( is_array( $licenses ) ) {- /**- * @var FS_Plugin_License[] $licenses- */- foreach ( $licenses as $license ) {- if ( ! $license->is_utilized() && $license->is_features_enabled() ) {- return true;- }- }- }-- return false;- }-- /**- * Check if plugin has any paid plans.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @param FS_Plugin_Plan[] $plans- *- * @return bool- */- function has_paid_plan( $plans ) {- if ( ! is_array( $plans ) || 0 === count( $plans ) ) {- return false;- }-- /**- * @var FS_Plugin_Plan[] $plans- */- for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {- if ( ! $plans[ $i ]->is_free() ) {- return true;- }- }-- return false;- }-- /**- * Check if plugin has any free plan, or is it premium only.- *- * Note: If no plans configured, assume plugin is free.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.7- *- * @param FS_Plugin_Plan[] $plans- *- * @return bool- */- function has_free_plan( $plans ) {- if ( ! is_array( $plans ) || 0 === count( $plans ) ) {- return true;- }-- /**- * @var FS_Plugin_Plan[] $plans- */- for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {- if ( $plans[ $i ]->is_free() ) {- return true;- }- }-- return false;- }-- /**- * Find all plans that have trial.- * Since 2.6.2 call get_filtered_plan- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @param FS_Plugin_Plan[] $plans- *- * @return FS_Plugin_Plan[]- */- function get_trial_plans( $plans ) {- return $this->get_filtered_plans( $plans, true );- }-- /**- * Find all plans that are not hidden and have trial.- *- * @author Daniele Alessandra (@danielealessandra)- *- * @param FS_Plugin_Plan[] $plans- *- * @return FS_Plugin_Plan[]- * @since 2.6.3- *- */- function get_visible_trial_plans( $plans ) {- return $this->get_filtered_plans( $plans, true, true );- }-- /**- * Find all plans filtered by trial or visibility.- *- * @author Daniele Alessandra (@danielealessandra)- *- * @param FS_Plugin_Plan[] $plans- * @param boolean $should_have_trials- * @param boolean $should_be_visible- *- * @return FS_Plugin_Plan[]- * @since 2.6.3- *- */- function get_filtered_plans( $plans, $should_have_trials = false, $should_be_visible = false ) {- $filtered_plans = array();-- if ( is_array( $plans ) && count( $plans ) > 0 ) {- foreach ( $plans as $plan ) {- if ( ( $should_have_trials && ! $plan->has_trial() ) || ( $should_be_visible && $plan->is_hidden ) ) {- continue;- }- $filtered_plans[] = $plan;- }- }-- return $filtered_plans;- }-- /**- * Check if plugin has any trial plan.- *- * @author Vova Feldman (@svovaf)- * @since 1.0.9- *- * @param FS_Plugin_Plan[] $plans- *- * @return bool- */- function has_trial_plan( $plans ) {- if ( ! is_array( $plans ) || 0 === count( $plans ) ) {- return true;- }-- /**- * @var FS_Plugin_Plan[] $plans- */- for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {- if ( $plans[ $i ]->has_trial() ) {- return true;- }- }-- return false;- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.6 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + class FS_Plan_Manager { + /** + * @var FS_Plan_Manager + */ + private static $_instance; + + /** + * @return FS_Plan_Manager + */ + static function instance() { + if ( ! isset( self::$_instance ) ) { + self::$_instance = new FS_Plan_Manager(); + } + + return self::$_instance; + } + + private function __construct() { + } + + /** + * @param FS_Plugin_License[] $licenses + * + * @return bool + */ + function has_premium_license( $licenses ) { + if ( is_array( $licenses ) ) { + /** + * @var FS_Plugin_License[] $licenses + */ + foreach ( $licenses as $license ) { + if ( ! $license->is_utilized() && $license->is_features_enabled() ) { + return true; + } + } + } + + return false; + } + + /** + * Check if plugin has any paid plans. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @param FS_Plugin_Plan[] $plans + * + * @return bool + */ + function has_paid_plan( $plans ) { + if ( ! is_array( $plans ) || 0 === count( $plans ) ) { + return false; + } + + /** + * @var FS_Plugin_Plan[] $plans + */ + for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) { + if ( ! $plans[ $i ]->is_free() ) { + return true; + } + } + + return false; + } + + /** + * Check if plugin has any free plan, or is it premium only. + * + * Note: If no plans configured, assume plugin is free. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.7 + * + * @param FS_Plugin_Plan[] $plans + * + * @return bool + */ + function has_free_plan( $plans ) { + if ( ! is_array( $plans ) || 0 === count( $plans ) ) { + return true; + } + + /** + * @var FS_Plugin_Plan[] $plans + */ + for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) { + if ( $plans[ $i ]->is_free() ) { + return true; + } + } + + return false; + } + + /** + * Find all plans that have trial. + * Since 2.6.2 call get_filtered_plan + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @param FS_Plugin_Plan[] $plans + * + * @return FS_Plugin_Plan[] + */ + function get_trial_plans( $plans ) { + return $this->get_filtered_plans( $plans, true ); + } + + /** + * Find all plans that are not hidden and have trial. + * + * @author Daniele Alessandra (@danielealessandra) + * + * @param FS_Plugin_Plan[] $plans + * + * @return FS_Plugin_Plan[] + * @since 2.6.3 + * + */ + function get_visible_trial_plans( $plans ) { + return $this->get_filtered_plans( $plans, true, true ); + } + + /** + * Find all plans filtered by trial or visibility. + * + * @author Daniele Alessandra (@danielealessandra) + * + * @param FS_Plugin_Plan[] $plans + * @param boolean $should_have_trials + * @param boolean $should_be_visible + * + * @return FS_Plugin_Plan[] + * @since 2.6.3 + * + */ + function get_filtered_plans( $plans, $should_have_trials = false, $should_be_visible = false ) { + $filtered_plans = array(); + + if ( is_array( $plans ) && count( $plans ) > 0 ) { + foreach ( $plans as $plan ) { + if ( ( $should_have_trials && ! $plan->has_trial() ) || ( $should_be_visible && $plan->is_hidden ) ) { + continue; + } + $filtered_plans[] = $plan; + } + } + + return $filtered_plans; + } + + /** + * Check if plugin has any trial plan. + * + * @author Vova Feldman (@svovaf) + * @since 1.0.9 + * + * @param FS_Plugin_Plan[] $plans + * + * @return bool + */ + function has_trial_plan( $plans ) { + if ( ! is_array( $plans ) || 0 === count( $plans ) ) { + return true; + } + + /** + * @var FS_Plugin_Plan[] $plans + */ + for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) { + if ( $plans[ $i ]->has_trial() ) { + return true; + } + } + + return false; + } }\ No newline at end of file
Analysis of the provided code diff:
---
**Vulnerability Existed:** no
**No Vulnerabilities Detected** - inc/freemius/includes/managers/class-fs-plan-manager.php (All lines)
**Old Code:**
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.0.6
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class FS_Plan_Manager {
// ... class implementation
}
```
**Fixed Code:**
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.0.6
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class FS_Plan_Manager {
// ... class implementation
}
```
**Explanation:**
This diff contains only whitespace changes (line ending normalization from CRLF to LF). The actual code logic, structure, and functionality remain identical between the two versions. No security vulnerabilities are introduced or fixed by this change. The file normalizes line endings throughout but no code modifications that could affect security are present.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/managers/index.php 2026-01-19 00:16:00.453015188 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/managers/index.php 2026-01-19 00:17:37.659045528 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
# Security Analysis Report ## File: inc/freemius/includes/managers/index.php **Vulnerability Existed: no** **No Vulnerabilities Detected** **Explanation:** This diff contains only whitespace and formatting changes. Specifically: - Line 1: No functional change (PHP opening tag remains identical) - Line 2: No functional change (comment remains identical) - Line 3: No functional change (comment remains identical) The changes appear to be line ending normalization or indentation adjustments that have no security implications. The file remains a PHP stub file that prevents direct directory access by hiding the file structure, which is a standard security practice. No code logic was added, removed, or modified that could introduce or fix vulnerabilities. --- **Summary:** This patch contains no security-relevant changes.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/sdk/Exceptions/index.php 2026-01-19 00:16:00.453015188 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/sdk/Exceptions/index.php 2026-01-19 00:17:37.659045528 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No CWE Vulnerability Identified - File: inc/freemius/includes/sdk/Exceptions/index.php Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace/formatting changes (likely tab vs. space normalization). No security-related code modifications are present. The file remains an empty PHP file designed to prevent direct access and directory listing, which is a legitimate security practice. No vulnerabilities were introduced or fixed in this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/sdk/index.php 2026-01-19 00:16:00.453015188 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/sdk/index.php 2026-01-19 00:17:37.663045776 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Vulnerability - File: inc/freemius/includes/sdk/index.php [Lines 1-3] Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace normalization changes (likely converting tabs/spaces or line endings). The file content and security posture remain identical. The index.php file is a legitimate security practice - leaving PHP files empty or with only comments prevents direct access exploitation and is not a vulnerability itself. No security fixes or regressions are present in this diff.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/supplements/fs-essential-functions-1.1.7.1.php 2026-01-19 00:16:00.453015188 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/supplements/fs-essential-functions-1.1.7.1.php 2026-01-19 00:17:37.663045776 +0000@@ -1,43 +1,43 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.7- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Find the plugin main file path based on any given file inside the plugin's folder.- *- * @author Vova Feldman (@svovaf)- * @since 1.1.7.1- *- * @param string $file Absolute path to a file inside a plugin's folder.- *- * @return string- */- function fs_find_direct_caller_plugin_file( $file ) {- /**- * All the code below will be executed once on activation.- * If the user changes the main plugin's file name, the file_exists()- * will catch it.- */- $all_plugins = fs_get_plugins( true );-- $file_real_path = fs_normalize_path( realpath( $file ) );-- // Get active plugin's main files real full names (might be symlinks).- foreach ( $all_plugins as $relative_path => $data ) {- if ( 0 === strpos( $file_real_path, fs_normalize_path( dirname( realpath( WP_PLUGIN_DIR . '/' . $relative_path ) ) . '/' ) ) ) {- if ( '.' !== dirname( trailingslashit( $relative_path ) ) ) {- return $relative_path;- }- }- }-- return null;- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.7 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Find the plugin main file path based on any given file inside the plugin's folder. + * + * @author Vova Feldman (@svovaf) + * @since 1.1.7.1 + * + * @param string $file Absolute path to a file inside a plugin's folder. + * + * @return string + */ + function fs_find_direct_caller_plugin_file( $file ) { + /** + * All the code below will be executed once on activation. + * If the user changes the main plugin's file name, the file_exists() + * will catch it. + */ + $all_plugins = fs_get_plugins( true ); + + $file_real_path = fs_normalize_path( realpath( $file ) ); + + // Get active plugin's main files real full names (might be symlinks). + foreach ( $all_plugins as $relative_path => $data ) { + if ( 0 === strpos( $file_real_path, fs_normalize_path( dirname( realpath( WP_PLUGIN_DIR . '/' . $relative_path ) ) . '/' ) ) ) { + if ( '.' !== dirname( trailingslashit( $relative_path ) ) ) { + return $relative_path; + } + } + } + + return null; + }
Based on my analysis of the provided diff, here is my assessment: **Vulnerability Existed: no** This diff contains only whitespace changes (line ending normalization from LF to CRLF or similar formatting adjustments). The actual code logic remains completely identical between the two versions. **Analysis Summary:** The changes are purely cosmetic: - Line endings have been normalized - No code logic has been modified - No new code has been introduced - No existing code has been removed Since the functional code is identical in both versions, there are **no security fixes or security vulnerabilities introduced** in this diff. The file `fs_find_direct_caller_plugin_file()` function performs path normalization and plugin directory checks, which are reasonable security practices for identifying legitimate plugin files. However, this functionality is unchanged between versions, so there is nothing to analyze as a "security fix."
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/supplements/fs-essential-functions-2.2.1.php 2026-01-19 00:16:00.453015188 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/supplements/fs-essential-functions-2.2.1.php 2026-01-19 00:17:37.663045776 +0000@@ -1,45 +1,45 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.2.1- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- if ( ! function_exists( 'fs_get_plugins' ) ) {- /**- * @author Leo Fajardo (@leorw)- * @since 2.2.1- *- * @param bool $delete_cache- *- * @return array- */- function fs_get_plugins( $delete_cache = false ) {- $cached_plugins = wp_cache_get( 'plugins', 'plugins' );- if ( ! is_array( $cached_plugins ) ) {- $cached_plugins = array();- }-- $plugin_folder = '';- if ( isset( $cached_plugins[ $plugin_folder ] ) ) {- $plugins = $cached_plugins[ $plugin_folder ];- } else {- if ( ! function_exists( 'get_plugins' ) ) {- require_once ABSPATH . 'wp-admin/includes/plugin.php';- }-- $plugins = get_plugins();-- if ( $delete_cache && is_plugin_active( 'woocommerce/woocommerce.php' ) ) {- wp_cache_delete( 'plugins', 'plugins' );- }- }-- return $plugins;- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.2.1 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + if ( ! function_exists( 'fs_get_plugins' ) ) { + /** + * @author Leo Fajardo (@leorw) + * @since 2.2.1 + * + * @param bool $delete_cache + * + * @return array + */ + function fs_get_plugins( $delete_cache = false ) { + $cached_plugins = wp_cache_get( 'plugins', 'plugins' ); + if ( ! is_array( $cached_plugins ) ) { + $cached_plugins = array(); + } + + $plugin_folder = ''; + if ( isset( $cached_plugins[ $plugin_folder ] ) ) { + $plugins = $cached_plugins[ $plugin_folder ]; + } else { + if ( ! function_exists( 'get_plugins' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + $plugins = get_plugins(); + + if ( $delete_cache && is_plugin_active( 'woocommerce/woocommerce.php' ) ) { + wp_cache_delete( 'plugins', 'plugins' ); + } + } + + return $plugins; + } }\ No newline at end of file
Vulnerability Existed: no No Security Vulnerabilities Detected - Line Ending Changes Only Explanation: The diff shows only whitespace/line-ending changes (CRLF to LF conversion) with no modifications to the actual code logic, structure, or security-critical functionality. The file content remains identical: - No changes to input validation or sanitization - No changes to authentication or authorization logic - No changes to file inclusion or require statements - No changes to function parameters or return values - No new or removed security-sensitive operations This is a formatting-only change that does not introduce, fix, or affect any security vulnerabilities.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/includes/supplements/index.php 2026-01-19 00:16:00.453015188 +0000+++ cache/filr-protection_1.2.12/inc/freemius/includes/supplements/index.php 2026-01-19 00:17:37.663045776 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Based on the provided code diff analysis: **Vulnerability Existed: no** **No CWE - N/A - inc/freemius/includes/supplements/index.php [1-3]** **Old Code:** ```php <?php // Silence is golden. ``` **Fixed Code:** ```php <?php // Silence is golden. ``` **Explanation:** This diff contains only whitespace/formatting changes (likely tab vs. space normalization). The file itself is an index.php file with only a comment, which is a common security practice to prevent directory listing and hide file structure on web servers. No actual code changes were made that could introduce or fix security vulnerabilities. The file's purpose—to prevent information disclosure through directory enumeration—remains unchanged and intact. This is not a security fix, but rather a code formatting/style adjustment with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/index.php 2026-01-19 00:16:00.453015188 +0000+++ cache/filr-protection_1.2.12/inc/freemius/index.php 2026-01-19 00:17:37.663045776 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Vulnerability Detected - Whitespace Changes Only Old Code: ```php <?php // Silence is golden. ``` Fixed Code: ```php <?php // Silence is golden. ``` Explanation: This diff contains only whitespace/formatting changes (line ending normalization). The file `inc/freemius/index.php` is a blank index file with only PHP opening tags and a comment. It serves no functional purpose and executes no code, so there are no security vulnerabilities being introduced or fixed. The changes do not modify any executable code, logic, or security-relevant content. This is a cosmetic change only.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/languages/index.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/languages/index.php 2026-01-19 00:17:37.671046273 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No CWE/Vulnerability Identified - N/A - inc/freemius/languages/index.php (Lines 1-3) Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace/formatting changes (likely tab/space normalization). The file is an index.php file that serves as an empty file to prevent directory listing, which is a legitimate security practice. No security vulnerabilities were introduced or fixed in this change. The file structure and content remain functionally identical.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/require.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/require.php 2026-01-19 00:17:37.671046273 +0000@@ -1,58 +1,58 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2016, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.9- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- // Configuration should be loaded first.- require_once dirname( __FILE__ ) . '/config.php';- require_once WP_FS__DIR_INCLUDES . '/fs-core-functions.php';- require_once WP_FS__DIR_INCLUDES . '/fs-html-escaping-functions.php';-- // Logger must be loaded before any other.- require_once WP_FS__DIR_INCLUDES . '/class-fs-logger.php';- require_once WP_FS__DIR_INCLUDES . '/debug/debug-bar-start.php';-- require_once WP_FS__DIR_INCLUDES . '/class-fs-garbage-collector.php';--// require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-abstract-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-option-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-gdpr-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-clone-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-permission-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-cache-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-notice-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-menu-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-key-value-storage.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-license-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plan-manager.php';- require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plugin-manager.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-entity.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-scope-entity.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-user.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-site.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-affiliate.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-affiliate-terms.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-info.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-tag.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-plan.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-pricing.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-payment.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-license.php';- require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-subscription.php';- require_once WP_FS__DIR_INCLUDES . '/class-fs-api.php';- require_once WP_FS__DIR_INCLUDES . '/class-fs-plugin-updater.php';- require_once WP_FS__DIR_INCLUDES . '/class-fs-security.php';- require_once WP_FS__DIR_INCLUDES . '/class-fs-options.php';- require_once WP_FS__DIR_INCLUDES . '/class-fs-storage.php';- require_once WP_FS__DIR_INCLUDES . '/class-fs-admin-notices.php';- require_once WP_FS__DIR_INCLUDES . '/class-freemius-abstract.php';- require_once WP_FS__DIR_INCLUDES . '/sdk/Exceptions/Exception.php';- require_once WP_FS__DIR_INCLUDES . '/class-freemius.php';+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2016, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.9 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + // Configuration should be loaded first. + require_once dirname( __FILE__ ) . '/config.php'; + require_once WP_FS__DIR_INCLUDES . '/fs-core-functions.php'; + require_once WP_FS__DIR_INCLUDES . '/fs-html-escaping-functions.php'; + + // Logger must be loaded before any other. + require_once WP_FS__DIR_INCLUDES . '/class-fs-logger.php'; + require_once WP_FS__DIR_INCLUDES . '/debug/debug-bar-start.php'; + + require_once WP_FS__DIR_INCLUDES . '/class-fs-garbage-collector.php'; + +// require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-abstract-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-option-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-gdpr-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-clone-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-permission-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-cache-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-notice-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-admin-menu-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-key-value-storage.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-license-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plan-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/managers/class-fs-plugin-manager.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-entity.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-scope-entity.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-user.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-site.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-affiliate.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-affiliate-terms.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-info.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-tag.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-plan.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-pricing.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-payment.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-plugin-license.php'; + require_once WP_FS__DIR_INCLUDES . '/entities/class-fs-subscription.php'; + require_once WP_FS__DIR_INCLUDES . '/class-fs-api.php'; + require_once WP_FS__DIR_INCLUDES . '/class-fs-plugin-updater.php'; + require_once WP_FS__DIR_INCLUDES . '/class-fs-security.php'; + require_once WP_FS__DIR_INCLUDES . '/class-fs-options.php'; + require_once WP_FS__DIR_INCLUDES . '/class-fs-storage.php'; + require_once WP_FS__DIR_INCLUDES . '/class-fs-admin-notices.php'; + require_once WP_FS__DIR_INCLUDES . '/class-freemius-abstract.php'; + require_once WP_FS__DIR_INCLUDES . '/sdk/Exceptions/Exception.php'; + require_once WP_FS__DIR_INCLUDES . '/class-freemius.php';
Vulnerability Existed: no No CWE - No Vulnerability Identified - inc/freemius/require.php (All lines) Old Code: Lines 1-58 with LF line endings Fixed Code: Lines 1-58 with CRLF line endings Explanation: This diff represents only a line ending normalization (LF to CRLF conversion). The actual code content is identical between versions 1.2.11 and 1.2.12. No security vulnerabilities are introduced or fixed by this change. The file consists entirely of require_once statements for configuration and class loading, with no functional code modifications that could affect security. Line ending changes do not introduce or remediate security issues.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/start.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/start.php 2026-01-19 00:17:37.671046273 +0000@@ -1,562 +1,562 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * Freemius SDK Version.- *- * @var string- */- $this_sdk_version = '2.7.4';-- #region SDK Selection Logic ---------------------------------------------------------------------- /**- * Special logic added on 1.1.6 to make sure that every Freemius powered plugin- * will ALWAYS be loaded with the newest SDK from the active Freemius powered plugins.- *- * Since Freemius SDK is backward compatible, this will make sure that all Freemius powered- * plugins will run correctly.- *- * @since 1.1.6- */-- global $fs_active_plugins;-- if ( ! function_exists( 'fs_find_caller_plugin_file' ) ) {- // Require SDK essentials.- require_once dirname( __FILE__ ) . '/includes/fs-essential-functions.php';- }-- /**- * This complex logic fixes symlink issues (e.g. with Vargant). The logic assumes- * that if it's a file from an SDK running in a theme, the location of the SDK- * is in the main theme's folder.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2.6- */- $file_path = fs_normalize_path( __FILE__ );- $fs_root_path = dirname( $file_path );-- // @todo: Remove this code after a few months when WP 6.3 usage is low enough.- global $wp_version;-- if (- ! function_exists( 'wp_get_current_user' ) &&- /**- * `get_stylesheet()` will rely on `wp_get_current_user()` when it is being filtered by `theme-previews.php`. That happens only when the site editor is loaded or when the site editor is sending REST requests.- * @see theme-previews.php:wp_get_theme_preview_path()- *- * @todo This behavior is already fixed in the core (WP 6.3.2+), and this code can be removed after a few months when WP 6.3 usage is low enough.- * @since WP 6.3.0- */- version_compare( $wp_version, '6.3', '>=' ) &&- version_compare( $wp_version, '6.3.1', '<=' ) &&- (- 'site-editor.php' === basename( $_SERVER['SCRIPT_FILENAME'] ) ||- (- function_exists( 'wp_is_json_request' ) &&- wp_is_json_request() &&- ! empty( $_GET['wp_theme_preview'] )- )- )- ) {- // Requiring this file since the call to get_stylesheet() below can trigger a call to wp_get_current_user() when previewing a theme.- require_once ABSPATH . 'wp-includes/pluggable.php';- }-- /**- * Get the themes directory where the active theme is located (not passing the stylesheet will make WordPress- * assume that the themes directory is inside `wp-content`.- *- * @author Leo Fajardo (@leorw)- * @since 2.2.3- */- $themes_directory = get_theme_root( get_stylesheet() );- $themes_directory_name = basename( $themes_directory );- $theme_candidate_basename = basename( dirname( $fs_root_path ) ) . '/' . basename( $fs_root_path );-- if ( $file_path == fs_normalize_path( realpath( trailingslashit( $themes_directory ) . $theme_candidate_basename . '/' . basename( $file_path ) ) )- ) {- $this_sdk_relative_path = '../' . $themes_directory_name . '/' . $theme_candidate_basename;- $is_theme = true;- } else {- $this_sdk_relative_path = plugin_basename( $fs_root_path );- $is_theme = false;- }-- if ( ! isset( $fs_active_plugins ) ) {- // Load all Freemius powered active plugins.- $fs_active_plugins = get_option( 'fs_active_plugins' );-- if ( ! is_object( $fs_active_plugins ) ) {- $fs_active_plugins = new stdClass();- }-- if ( ! isset( $fs_active_plugins->plugins ) ) {- $fs_active_plugins->plugins = array();- }- }-- if ( empty( $fs_active_plugins->abspath ) ) {- /**- * Store the WP install absolute path reference to identify environment change- * while replicating the storage.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.7- */- $fs_active_plugins->abspath = ABSPATH;- } else {- if ( ABSPATH !== $fs_active_plugins->abspath ) {- /**- * WordPress path has changed, cleanup the SDK references cache.- * This resolves issues triggered when spinning a staging environments- * while replicating the database.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.7- */- $fs_active_plugins->abspath = ABSPATH;- $fs_active_plugins->plugins = array();- unset( $fs_active_plugins->newest );- } else {- /**- * Make sure SDK references are still valid. This resolves- * issues when users hard delete modules via FTP.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.1.7- */- $has_changes = false;- foreach ( $fs_active_plugins->plugins as $sdk_path => $data ) {- if ( ! file_exists( ( isset( $data->type ) && 'theme' === $data->type ? $themes_directory : WP_PLUGIN_DIR ) . '/' . $sdk_path ) ) {- unset( $fs_active_plugins->plugins[ $sdk_path ] );-- if (- ! empty( $fs_active_plugins->newest ) &&- $sdk_path === $fs_active_plugins->newest->sdk_path- ) {- unset( $fs_active_plugins->newest );- }-- $has_changes = true;- }- }-- if ( $has_changes ) {- if ( empty( $fs_active_plugins->plugins ) ) {- unset( $fs_active_plugins->newest );- }-- update_option( 'fs_active_plugins', $fs_active_plugins );- }- }- }-- if ( ! function_exists( 'fs_find_direct_caller_plugin_file' ) ) {- require_once dirname( __FILE__ ) . '/includes/supplements/fs-essential-functions-1.1.7.1.php';- }-- if ( ! function_exists( 'fs_get_plugins' ) ) {- require_once dirname( __FILE__ ) . '/includes/supplements/fs-essential-functions-2.2.1.php';- }-- // Update current SDK info based on the SDK path.- if ( ! isset( $fs_active_plugins->plugins[ $this_sdk_relative_path ] ) ||- $this_sdk_version != $fs_active_plugins->plugins[ $this_sdk_relative_path ]->version- ) {- if ( $is_theme ) {- $plugin_path = basename( dirname( $this_sdk_relative_path ) );- } else {- $plugin_path = plugin_basename( fs_find_direct_caller_plugin_file( $file_path ) );- }-- $fs_active_plugins->plugins[ $this_sdk_relative_path ] = (object) array(- 'version' => $this_sdk_version,- 'type' => ( $is_theme ? 'theme' : 'plugin' ),- 'timestamp' => time(),- 'plugin_path' => $plugin_path,- );- }-- $is_current_sdk_newest = isset( $fs_active_plugins->newest ) && ( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path );-- if ( ! isset( $fs_active_plugins->newest ) ) {- /**- * This will be executed only once, for the first time a Freemius powered plugin is activated.- */- fs_update_sdk_newest_version( $this_sdk_relative_path, $fs_active_plugins->plugins[ $this_sdk_relative_path ]->plugin_path );-- $is_current_sdk_newest = true;- } else if ( version_compare( $fs_active_plugins->newest->version, $this_sdk_version, '<' ) ) {- /**- * Current SDK is newer than the newest stored SDK.- */- fs_update_sdk_newest_version( $this_sdk_relative_path, $fs_active_plugins->plugins[ $this_sdk_relative_path ]->plugin_path );-- if ( class_exists( 'Freemius' ) ) {- // Older SDK version was already loaded.-- if ( ! $fs_active_plugins->newest->in_activation ) {- // Re-order plugins to load this plugin first.- fs_newest_sdk_plugin_first();- }-- // Refresh page.- fs_redirect( $_SERVER['REQUEST_URI'] );- }- } else {- if ( ! function_exists( 'get_plugins' ) ) {- require_once ABSPATH . 'wp-admin/includes/plugin.php';- }-- $fs_newest_sdk = $fs_active_plugins->newest;- $fs_newest_sdk = $fs_active_plugins->plugins[ $fs_newest_sdk->sdk_path ];-- $is_newest_sdk_type_theme = ( isset( $fs_newest_sdk->type ) && 'theme' === $fs_newest_sdk->type );-- if ( ! $is_newest_sdk_type_theme ) {- $is_newest_sdk_plugin_active = is_plugin_active( $fs_newest_sdk->plugin_path );- } else {- $current_theme = wp_get_theme();- $is_newest_sdk_plugin_active = ( $current_theme->stylesheet === $fs_newest_sdk->plugin_path );-- $current_theme_parent = $current_theme->parent();-- /**- * If the current theme is a child of the theme that has the newest SDK, this prevents a redirects loop- * from happening by keeping the SDK info stored in the `fs_active_plugins` option.- */- if ( ! $is_newest_sdk_plugin_active && $current_theme_parent instanceof WP_Theme ) {- $is_newest_sdk_plugin_active = ( $fs_newest_sdk->plugin_path === $current_theme_parent->stylesheet );- }- }-- if ( $is_current_sdk_newest &&- ! $is_newest_sdk_plugin_active &&- ! $fs_active_plugins->newest->in_activation- ) {- // If current SDK is the newest and the plugin is NOT active, it means- // that the current plugin in activation mode.- $fs_active_plugins->newest->in_activation = true;- update_option( 'fs_active_plugins', $fs_active_plugins );- }-- if ( ! $is_theme ) {- $sdk_starter_path = fs_normalize_path( WP_PLUGIN_DIR . '/' . $this_sdk_relative_path . '/start.php' );- } else {- $sdk_starter_path = fs_normalize_path(- $themes_directory- . '/'- . str_replace( "../{$themes_directory_name}/", '', $this_sdk_relative_path )- . '/start.php' );- }-- $is_newest_sdk_path_valid = ( $is_newest_sdk_plugin_active || $fs_active_plugins->newest->in_activation ) && file_exists( $sdk_starter_path );-- if ( ! $is_newest_sdk_path_valid && ! $is_current_sdk_newest ) {- // Plugin with newest SDK is no longer active, or SDK was moved to a different location.- unset( $fs_active_plugins->plugins[ $fs_active_plugins->newest->sdk_path ] );- }-- if ( ! ( $is_newest_sdk_plugin_active || $fs_active_plugins->newest->in_activation ) ||- ! $is_newest_sdk_path_valid ||- // Is newest SDK downgraded.- ( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path &&- version_compare( $fs_active_plugins->newest->version, $this_sdk_version, '>' ) )- ) {- /**- * Plugin with newest SDK is no longer active.- * OR- * The newest SDK was in the current plugin. BUT, seems like the version of- * the SDK was downgraded to a lower SDK.- */- // Find the active plugin with the newest SDK version and update the newest reference.- fs_fallback_to_newest_active_sdk();- } else {- if ( $is_newest_sdk_plugin_active &&- $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path &&- ( $fs_active_plugins->newest->in_activation ||- ( class_exists( 'Freemius' ) && ( ! defined( 'WP_FS__SDK_VERSION' ) || version_compare( WP_FS__SDK_VERSION, $this_sdk_version, '<' ) ) )- )-- ) {- if ( $fs_active_plugins->newest->in_activation && ! $is_newest_sdk_type_theme ) {- // Plugin no more in activation.- $fs_active_plugins->newest->in_activation = false;- update_option( 'fs_active_plugins', $fs_active_plugins );- }-- // Reorder plugins to load plugin with newest SDK first.- if ( fs_newest_sdk_plugin_first() ) {- // Refresh page after re-order to make sure activated plugin loads newest SDK.- if ( class_exists( 'Freemius' ) ) {- fs_redirect( $_SERVER['REQUEST_URI'] );- }- }- }- }- }-- if ( class_exists( 'Freemius' ) ) {- // SDK was already loaded.- return;- }-- if ( version_compare( $this_sdk_version, $fs_active_plugins->newest->version, '<' ) ) {- $newest_sdk = $fs_active_plugins->plugins[ $fs_active_plugins->newest->sdk_path ];-- $plugins_or_theme_dir_path = ( ! isset( $newest_sdk->type ) || 'theme' !== $newest_sdk->type ) ?- WP_PLUGIN_DIR :- $themes_directory;-- $newest_sdk_starter = fs_normalize_path(- $plugins_or_theme_dir_path- . '/'- . str_replace( "../{$themes_directory_name}/", '', $fs_active_plugins->newest->sdk_path )- . '/start.php' );-- if ( file_exists( $newest_sdk_starter ) ) {- // Reorder plugins to load plugin with newest SDK first.- fs_newest_sdk_plugin_first();-- // There's a newer SDK version, load it instead of the current one!- require_once $newest_sdk_starter;-- return;- }- }-- #endregion SDK Selection Logic ---------------------------------------------------------------------- #region Hooks & Filters Collection ---------------------------------------------------------------------- /**- * Freemius hooks (actions & filters) tags structure:- *- * fs_{filter/action_name}_{plugin_slug}- *- * --------------------------------------------------------- *- * Usage with WordPress' add_action() / add_filter():- *- * add_action('fs_{filter/action_name}_{plugin_slug}', $callable);- *- * --------------------------------------------------------- *- * Usage with Freemius' instance add_action() / add_filter():- *- * // No need to add 'fs_' prefix nor '_{plugin_slug}' suffix.- * my_freemius()->add_action('{action_name}', $callable);- *- * --------------------------------------------------------- *- * Freemius filters collection:- *- * fs_connect_url_{plugin_slug}- * fs_trial_promotion_message_{plugin_slug}- * fs_is_long_term_user_{plugin_slug}- * fs_uninstall_reasons_{plugin_slug}- * fs_is_plugin_update_{plugin_slug}- * fs_api_domains_{plugin_slug}- * fs_email_template_sections_{plugin_slug}- * fs_support_forum_submenu_{plugin_slug}- * fs_support_forum_url_{plugin_slug}- * fs_connect_message_{plugin_slug}- * fs_connect_message_on_update_{plugin_slug}- * fs_uninstall_confirmation_message_{plugin_slug}- * fs_pending_activation_message_{plugin_slug}- * fs_is_submenu_visible_{plugin_slug}- * fs_plugin_icon_{plugin_slug}- * fs_show_trial_{plugin_slug}- *- * --------------------------------------------------------- *- * Freemius actions collection:- *- * fs_after_license_loaded_{plugin_slug}- * fs_after_license_change_{plugin_slug}- * fs_after_plans_sync_{plugin_slug}- *- * fs_after_account_details_{plugin_slug}- * fs_after_account_user_sync_{plugin_slug}- * fs_after_account_plan_sync_{plugin_slug}- * fs_before_account_load_{plugin_slug}- * fs_after_account_connection_{plugin_slug}- * fs_account_property_edit_{plugin_slug}- * fs_account_email_verified_{plugin_slug}- * fs_account_page_load_before_departure_{plugin_slug}- * fs_before_account_delete_{plugin_slug}- * fs_after_account_delete_{plugin_slug}- *- * fs_sdk_version_update_{plugin_slug}- * fs_plugin_version_update_{plugin_slug}- *- * fs_initiated_{plugin_slug}- * fs_after_init_plugin_registered_{plugin_slug}- * fs_after_init_plugin_anonymous_{plugin_slug}- * fs_after_init_plugin_pending_activations_{plugin_slug}- * fs_after_init_addon_registered_{plugin_slug}- * fs_after_init_addon_anonymous_{plugin_slug}- * fs_after_init_addon_pending_activations_{plugin_slug}- *- * fs_after_premium_version_activation_{plugin_slug}- * fs_after_free_version_reactivation_{plugin_slug}- *- * fs_after_uninstall_{plugin_slug}- * fs_before_admin_menu_init_{plugin_slug}- */-- #endregion Hooks & Filters Collection ---------------------------------------------------------------------- if ( ! class_exists( 'Freemius' ) ) {-- if ( ! defined( 'WP_FS__SDK_VERSION' ) ) {- define( 'WP_FS__SDK_VERSION', $this_sdk_version );- }-- $plugins_or_theme_dir_path = fs_normalize_path( trailingslashit( $is_theme ?- $themes_directory :- WP_PLUGIN_DIR ) );-- if ( 0 === strpos( $file_path, $plugins_or_theme_dir_path ) ) {- // No symlinks- } else {- /**- * This logic finds the SDK symlink and set WP_FS__DIR to use it.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2.5- */- $sdk_symlink = null;-- // Try to load SDK's symlink from cache.- if ( isset( $fs_active_plugins->plugins[ $this_sdk_relative_path ] ) &&- is_object( $fs_active_plugins->plugins[ $this_sdk_relative_path ] ) &&- ! empty( $fs_active_plugins->plugins[ $this_sdk_relative_path ]->sdk_symlink )- ) {- $sdk_symlink = $fs_active_plugins->plugins[ $this_sdk_relative_path ]->sdk_symlink;- if ( 0 === strpos( $sdk_symlink, $plugins_or_theme_dir_path ) ) {- /**- * Make the symlink path relative.- *- * @author Leo Fajardo (@leorw)- */- $sdk_symlink = substr( $sdk_symlink, strlen( $plugins_or_theme_dir_path ) );-- $fs_active_plugins->plugins[ $this_sdk_relative_path ]->sdk_symlink = $sdk_symlink;- update_option( 'fs_active_plugins', $fs_active_plugins );- }-- $realpath = realpath( $plugins_or_theme_dir_path . $sdk_symlink );- if ( ! is_string( $realpath ) || ! file_exists( $realpath ) ) {- $sdk_symlink = null;- }- }-- if ( empty( $sdk_symlink ) ) // Has symlinks, therefore, we need to configure WP_FS__DIR based on the symlink.- {- $partial_path_right = basename( $file_path );- $partial_path_left = dirname( $file_path );- $realpath = realpath( $plugins_or_theme_dir_path . $partial_path_right );-- while ( '/' !== $partial_path_left &&- ( false === $realpath || $file_path !== fs_normalize_path( $realpath ) )- ) {- $partial_path_right = trailingslashit( basename( $partial_path_left ) ) . $partial_path_right;- $partial_path_left_prev = $partial_path_left;- $partial_path_left = dirname( $partial_path_left_prev );-- /**- * Avoid infinite loop if for example `$partial_path_left_prev` is `C:/`, in this case,- * `dirname( 'C:/' )` will return `C:/`.- *- * @author Leo Fajardo (@leorw)- */- if ( $partial_path_left === $partial_path_left_prev ) {- $partial_path_left = '';- break;- }-- $realpath = realpath( $plugins_or_theme_dir_path . $partial_path_right );- }-- if ( ! empty( $partial_path_left ) && '/' !== $partial_path_left ) {- $sdk_symlink = fs_normalize_path( dirname( $partial_path_right ) );-- // Cache value.- if ( isset( $fs_active_plugins->plugins[ $this_sdk_relative_path ] ) &&- is_object( $fs_active_plugins->plugins[ $this_sdk_relative_path ] )- ) {- $fs_active_plugins->plugins[ $this_sdk_relative_path ]->sdk_symlink = $sdk_symlink;- update_option( 'fs_active_plugins', $fs_active_plugins );- }- }- }-- if ( ! empty( $sdk_symlink ) ) {- // Set SDK dir to the symlink path.- define( 'WP_FS__DIR', $plugins_or_theme_dir_path . $sdk_symlink );- }- }-- // Load SDK files.- require_once dirname( __FILE__ ) . '/require.php';-- /**- * Quick shortcut to get Freemius for specified plugin.- * Used by various templates.- *- * @param number $module_id- *- * @return Freemius- */- function freemius( $module_id ) {- return Freemius::instance( $module_id );- }-- /**- * @param string $slug- * @param number $plugin_id- * @param string $public_key- * @param bool $is_live Is live or test plugin.- * @param bool $is_premium Hints freemius if running the premium plugin or not.- *- * @return Freemius- *- * @deprecated Please use fs_dynamic_init().- */- function fs_init( $slug, $plugin_id, $public_key, $is_live = true, $is_premium = true ) {- $fs = Freemius::instance( $plugin_id, $slug, true );- $fs->init( $plugin_id, $public_key, $is_live, $is_premium );-- return $fs;- }-- /**- * @param array <string,string|bool|array> $module Plugin or Theme details.- *- * @return Freemius- * @throws Freemius_Exception- */- function fs_dynamic_init( $module ) {- $fs = Freemius::instance( $module['id'], $module['slug'], true );- $fs->dynamic_init( $module );-- return $fs;- }-- function fs_dump_log() {- FS_Logger::dump();- }- }+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * Freemius SDK Version. + * + * @var string + */ + $this_sdk_version = '2.7.4'; + + #region SDK Selection Logic -------------------------------------------------------------------- + + /** + * Special logic added on 1.1.6 to make sure that every Freemius powered plugin + * will ALWAYS be loaded with the newest SDK from the active Freemius powered plugins. + * + * Since Freemius SDK is backward compatible, this will make sure that all Freemius powered + * plugins will run correctly. + * + * @since 1.1.6 + */ + + global $fs_active_plugins; + + if ( ! function_exists( 'fs_find_caller_plugin_file' ) ) { + // Require SDK essentials. + require_once dirname( __FILE__ ) . '/includes/fs-essential-functions.php'; + } + + /** + * This complex logic fixes symlink issues (e.g. with Vargant). The logic assumes + * that if it's a file from an SDK running in a theme, the location of the SDK + * is in the main theme's folder. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.2.6 + */ + $file_path = fs_normalize_path( __FILE__ ); + $fs_root_path = dirname( $file_path ); + + // @todo: Remove this code after a few months when WP 6.3 usage is low enough. + global $wp_version; + + if ( + ! function_exists( 'wp_get_current_user' ) && + /** + * `get_stylesheet()` will rely on `wp_get_current_user()` when it is being filtered by `theme-previews.php`. That happens only when the site editor is loaded or when the site editor is sending REST requests. + * @see theme-previews.php:wp_get_theme_preview_path() + * + * @todo This behavior is already fixed in the core (WP 6.3.2+), and this code can be removed after a few months when WP 6.3 usage is low enough. + * @since WP 6.3.0 + */ + version_compare( $wp_version, '6.3', '>=' ) && + version_compare( $wp_version, '6.3.1', '<=' ) && + ( + 'site-editor.php' === basename( $_SERVER['SCRIPT_FILENAME'] ) || + ( + function_exists( 'wp_is_json_request' ) && + wp_is_json_request() && + ! empty( $_GET['wp_theme_preview'] ) + ) + ) + ) { + // Requiring this file since the call to get_stylesheet() below can trigger a call to wp_get_current_user() when previewing a theme. + require_once ABSPATH . 'wp-includes/pluggable.php'; + } + + /** + * Get the themes directory where the active theme is located (not passing the stylesheet will make WordPress + * assume that the themes directory is inside `wp-content`. + * + * @author Leo Fajardo (@leorw) + * @since 2.2.3 + */ + $themes_directory = get_theme_root( get_stylesheet() ); + $themes_directory_name = basename( $themes_directory ); + $theme_candidate_basename = basename( dirname( $fs_root_path ) ) . '/' . basename( $fs_root_path ); + + if ( $file_path == fs_normalize_path( realpath( trailingslashit( $themes_directory ) . $theme_candidate_basename . '/' . basename( $file_path ) ) ) + ) { + $this_sdk_relative_path = '../' . $themes_directory_name . '/' . $theme_candidate_basename; + $is_theme = true; + } else { + $this_sdk_relative_path = plugin_basename( $fs_root_path ); + $is_theme = false; + } + + if ( ! isset( $fs_active_plugins ) ) { + // Load all Freemius powered active plugins. + $fs_active_plugins = get_option( 'fs_active_plugins' ); + + if ( ! is_object( $fs_active_plugins ) ) { + $fs_active_plugins = new stdClass(); + } + + if ( ! isset( $fs_active_plugins->plugins ) ) { + $fs_active_plugins->plugins = array(); + } + } + + if ( empty( $fs_active_plugins->abspath ) ) { + /** + * Store the WP install absolute path reference to identify environment change + * while replicating the storage. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.1.7 + */ + $fs_active_plugins->abspath = ABSPATH; + } else { + if ( ABSPATH !== $fs_active_plugins->abspath ) { + /** + * WordPress path has changed, cleanup the SDK references cache. + * This resolves issues triggered when spinning a staging environments + * while replicating the database. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.1.7 + */ + $fs_active_plugins->abspath = ABSPATH; + $fs_active_plugins->plugins = array(); + unset( $fs_active_plugins->newest ); + } else { + /** + * Make sure SDK references are still valid. This resolves + * issues when users hard delete modules via FTP. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.1.7 + */ + $has_changes = false; + foreach ( $fs_active_plugins->plugins as $sdk_path => $data ) { + if ( ! file_exists( ( isset( $data->type ) && 'theme' === $data->type ? $themes_directory : WP_PLUGIN_DIR ) . '/' . $sdk_path ) ) { + unset( $fs_active_plugins->plugins[ $sdk_path ] ); + + if ( + ! empty( $fs_active_plugins->newest ) && + $sdk_path === $fs_active_plugins->newest->sdk_path + ) { + unset( $fs_active_plugins->newest ); + } + + $has_changes = true; + } + } + + if ( $has_changes ) { + if ( empty( $fs_active_plugins->plugins ) ) { + unset( $fs_active_plugins->newest ); + } + + update_option( 'fs_active_plugins', $fs_active_plugins ); + } + } + } + + if ( ! function_exists( 'fs_find_direct_caller_plugin_file' ) ) { + require_once dirname( __FILE__ ) . '/includes/supplements/fs-essential-functions-1.1.7.1.php'; + } + + if ( ! function_exists( 'fs_get_plugins' ) ) { + require_once dirname( __FILE__ ) . '/includes/supplements/fs-essential-functions-2.2.1.php'; + } + + // Update current SDK info based on the SDK path. + if ( ! isset( $fs_active_plugins->plugins[ $this_sdk_relative_path ] ) || + $this_sdk_version != $fs_active_plugins->plugins[ $this_sdk_relative_path ]->version + ) { + if ( $is_theme ) { + $plugin_path = basename( dirname( $this_sdk_relative_path ) ); + } else { + $plugin_path = plugin_basename( fs_find_direct_caller_plugin_file( $file_path ) ); + } + + $fs_active_plugins->plugins[ $this_sdk_relative_path ] = (object) array( + 'version' => $this_sdk_version, + 'type' => ( $is_theme ? 'theme' : 'plugin' ), + 'timestamp' => time(), + 'plugin_path' => $plugin_path, + ); + } + + $is_current_sdk_newest = isset( $fs_active_plugins->newest ) && ( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path ); + + if ( ! isset( $fs_active_plugins->newest ) ) { + /** + * This will be executed only once, for the first time a Freemius powered plugin is activated. + */ + fs_update_sdk_newest_version( $this_sdk_relative_path, $fs_active_plugins->plugins[ $this_sdk_relative_path ]->plugin_path ); + + $is_current_sdk_newest = true; + } else if ( version_compare( $fs_active_plugins->newest->version, $this_sdk_version, '<' ) ) { + /** + * Current SDK is newer than the newest stored SDK. + */ + fs_update_sdk_newest_version( $this_sdk_relative_path, $fs_active_plugins->plugins[ $this_sdk_relative_path ]->plugin_path ); + + if ( class_exists( 'Freemius' ) ) { + // Older SDK version was already loaded. + + if ( ! $fs_active_plugins->newest->in_activation ) { + // Re-order plugins to load this plugin first. + fs_newest_sdk_plugin_first(); + } + + // Refresh page. + fs_redirect( $_SERVER['REQUEST_URI'] ); + } + } else { + if ( ! function_exists( 'get_plugins' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + + $fs_newest_sdk = $fs_active_plugins->newest; + $fs_newest_sdk = $fs_active_plugins->plugins[ $fs_newest_sdk->sdk_path ]; + + $is_newest_sdk_type_theme = ( isset( $fs_newest_sdk->type ) && 'theme' === $fs_newest_sdk->type ); + + if ( ! $is_newest_sdk_type_theme ) { + $is_newest_sdk_plugin_active = is_plugin_active( $fs_newest_sdk->plugin_path ); + } else { + $current_theme = wp_get_theme(); + $is_newest_sdk_plugin_active = ( $current_theme->stylesheet === $fs_newest_sdk->plugin_path ); + + $current_theme_parent = $current_theme->parent(); + + /** + * If the current theme is a child of the theme that has the newest SDK, this prevents a redirects loop + * from happening by keeping the SDK info stored in the `fs_active_plugins` option. + */ + if ( ! $is_newest_sdk_plugin_active && $current_theme_parent instanceof WP_Theme ) { + $is_newest_sdk_plugin_active = ( $fs_newest_sdk->plugin_path === $current_theme_parent->stylesheet ); + } + } + + if ( $is_current_sdk_newest && + ! $is_newest_sdk_plugin_active && + ! $fs_active_plugins->newest->in_activation + ) { + // If current SDK is the newest and the plugin is NOT active, it means + // that the current plugin in activation mode. + $fs_active_plugins->newest->in_activation = true; + update_option( 'fs_active_plugins', $fs_active_plugins ); + } + + if ( ! $is_theme ) { + $sdk_starter_path = fs_normalize_path( WP_PLUGIN_DIR . '/' . $this_sdk_relative_path . '/start.php' ); + } else { + $sdk_starter_path = fs_normalize_path( + $themes_directory + . '/' + . str_replace( "../{$themes_directory_name}/", '', $this_sdk_relative_path ) + . '/start.php' ); + } + + $is_newest_sdk_path_valid = ( $is_newest_sdk_plugin_active || $fs_active_plugins->newest->in_activation ) && file_exists( $sdk_starter_path ); + + if ( ! $is_newest_sdk_path_valid && ! $is_current_sdk_newest ) { + // Plugin with newest SDK is no longer active, or SDK was moved to a different location. + unset( $fs_active_plugins->plugins[ $fs_active_plugins->newest->sdk_path ] ); + } + + if ( ! ( $is_newest_sdk_plugin_active || $fs_active_plugins->newest->in_activation ) || + ! $is_newest_sdk_path_valid || + // Is newest SDK downgraded. + ( $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path && + version_compare( $fs_active_plugins->newest->version, $this_sdk_version, '>' ) ) + ) { + /** + * Plugin with newest SDK is no longer active. + * OR + * The newest SDK was in the current plugin. BUT, seems like the version of + * the SDK was downgraded to a lower SDK. + */ + // Find the active plugin with the newest SDK version and update the newest reference. + fs_fallback_to_newest_active_sdk(); + } else { + if ( $is_newest_sdk_plugin_active && + $this_sdk_relative_path == $fs_active_plugins->newest->sdk_path && + ( $fs_active_plugins->newest->in_activation || + ( class_exists( 'Freemius' ) && ( ! defined( 'WP_FS__SDK_VERSION' ) || version_compare( WP_FS__SDK_VERSION, $this_sdk_version, '<' ) ) ) + ) + + ) { + if ( $fs_active_plugins->newest->in_activation && ! $is_newest_sdk_type_theme ) { + // Plugin no more in activation. + $fs_active_plugins->newest->in_activation = false; + update_option( 'fs_active_plugins', $fs_active_plugins ); + } + + // Reorder plugins to load plugin with newest SDK first. + if ( fs_newest_sdk_plugin_first() ) { + // Refresh page after re-order to make sure activated plugin loads newest SDK. + if ( class_exists( 'Freemius' ) ) { + fs_redirect( $_SERVER['REQUEST_URI'] ); + } + } + } + } + } + + if ( class_exists( 'Freemius' ) ) { + // SDK was already loaded. + return; + } + + if ( version_compare( $this_sdk_version, $fs_active_plugins->newest->version, '<' ) ) { + $newest_sdk = $fs_active_plugins->plugins[ $fs_active_plugins->newest->sdk_path ]; + + $plugins_or_theme_dir_path = ( ! isset( $newest_sdk->type ) || 'theme' !== $newest_sdk->type ) ? + WP_PLUGIN_DIR : + $themes_directory; + + $newest_sdk_starter = fs_normalize_path( + $plugins_or_theme_dir_path + . '/' + . str_replace( "../{$themes_directory_name}/", '', $fs_active_plugins->newest->sdk_path ) + . '/start.php' ); + + if ( file_exists( $newest_sdk_starter ) ) { + // Reorder plugins to load plugin with newest SDK first. + fs_newest_sdk_plugin_first(); + + // There's a newer SDK version, load it instead of the current one! + require_once $newest_sdk_starter; + + return; + } + } + + #endregion SDK Selection Logic -------------------------------------------------------------------- + + #region Hooks & Filters Collection -------------------------------------------------------------------- + + /** + * Freemius hooks (actions & filters) tags structure: + * + * fs_{filter/action_name}_{plugin_slug} + * + * -------------------------------------------------------- + * + * Usage with WordPress' add_action() / add_filter(): + * + * add_action('fs_{filter/action_name}_{plugin_slug}', $callable); + * + * -------------------------------------------------------- + * + * Usage with Freemius' instance add_action() / add_filter(): + * + * // No need to add 'fs_' prefix nor '_{plugin_slug}' suffix. + * my_freemius()->add_action('{action_name}', $callable); + * + * -------------------------------------------------------- + * + * Freemius filters collection: + * + * fs_connect_url_{plugin_slug} + * fs_trial_promotion_message_{plugin_slug} + * fs_is_long_term_user_{plugin_slug} + * fs_uninstall_reasons_{plugin_slug} + * fs_is_plugin_update_{plugin_slug} + * fs_api_domains_{plugin_slug} + * fs_email_template_sections_{plugin_slug} + * fs_support_forum_submenu_{plugin_slug} + * fs_support_forum_url_{plugin_slug} + * fs_connect_message_{plugin_slug} + * fs_connect_message_on_update_{plugin_slug} + * fs_uninstall_confirmation_message_{plugin_slug} + * fs_pending_activation_message_{plugin_slug} + * fs_is_submenu_visible_{plugin_slug} + * fs_plugin_icon_{plugin_slug} + * fs_show_trial_{plugin_slug} + * + * -------------------------------------------------------- + * + * Freemius actions collection: + * + * fs_after_license_loaded_{plugin_slug} + * fs_after_license_change_{plugin_slug} + * fs_after_plans_sync_{plugin_slug} + * + * fs_after_account_details_{plugin_slug} + * fs_after_account_user_sync_{plugin_slug} + * fs_after_account_plan_sync_{plugin_slug} + * fs_before_account_load_{plugin_slug} + * fs_after_account_connection_{plugin_slug} + * fs_account_property_edit_{plugin_slug} + * fs_account_email_verified_{plugin_slug} + * fs_account_page_load_before_departure_{plugin_slug} + * fs_before_account_delete_{plugin_slug} + * fs_after_account_delete_{plugin_slug} + * + * fs_sdk_version_update_{plugin_slug} + * fs_plugin_version_update_{plugin_slug} + * + * fs_initiated_{plugin_slug} + * fs_after_init_plugin_registered_{plugin_slug} + * fs_after_init_plugin_anonymous_{plugin_slug} + * fs_after_init_plugin_pending_activations_{plugin_slug} + * fs_after_init_addon_registered_{plugin_slug} + * fs_after_init_addon_anonymous_{plugin_slug} + * fs_after_init_addon_pending_activations_{plugin_slug} + * + * fs_after_premium_version_activation_{plugin_slug} + * fs_after_free_version_reactivation_{plugin_slug} + * + * fs_after_uninstall_{plugin_slug} + * fs_before_admin_menu_init_{plugin_slug} + */ + + #endregion Hooks & Filters Collection -------------------------------------------------------------------- + + if ( ! class_exists( 'Freemius' ) ) { + + if ( ! defined( 'WP_FS__SDK_VERSION' ) ) { + define( 'WP_FS__SDK_VERSION', $this_sdk_version ); + } + + $plugins_or_theme_dir_path = fs_normalize_path( trailingslashit( $is_theme ? + $themes_directory : + WP_PLUGIN_DIR ) ); + + if ( 0 === strpos( $file_path, $plugins_or_theme_dir_path ) ) { + // No symlinks + } else { + /**
I'll analyze this diff for security vulnerabilities. **Analysis:** Vulnerability Existed: **no** The diff shows a **line ending change** (LF vs CRLF) throughout the file, converting the entire file from Windows-style line endings (CRLF - `\r\n`) to Unix-style line endings (LF - `\n`). This is a formatting change only. **Details:** - **File:** inc/freemius/start.php - **Lines:** 1-562 (entire file) - **Change Type:** Line ending normalization (CRLF → LF) **Old Code:** ``` <?php[CRLF] /**[CRLF] * @package Freemius[CRLF] ... ``` **Fixed Code:** ``` <?php[LF] /**[LF] * @package Freemius[LF] ... ``` **Explanation:** This is a benign formatting change with no security implications. Line ending normalization (CRLF to LF) is purely cosmetic and does not: - Introduce or fix security vulnerabilities - Change functionality or behavior - Affect code execution - Modify any logic, data handling, or security controls This type of change is typically done for consistency across different development environments or to comply with version control system settings. No vulnerabilities are present in this diff.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/account/billing.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/account/billing.php 2026-01-19 00:17:37.671046273 +0000@@ -1,423 +1,423 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2016, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );-- $slug = $fs->get_slug();-- $edit_text = fs_text_x_inline( 'Edit', 'verb', 'edit', $slug );- $update_text = fs_text_x_inline( 'Update', 'verb', 'update', $slug );-- $billing = $fs->_fetch_billing();- $has_billing = ( $billing instanceof FS_Billing );- if ( ! $has_billing ) {- $billing = new FS_Billing();- }-?>-<!-- Billing -->-<div class="postbox">- <div id="fs_billing">- <h3><span class="dashicons dashicons-portfolio"></span> <?php fs_esc_html_echo_inline( 'Billing', 'billing', $slug ) ?></h3>- <table id="fs_billing_address"<?php if ( $has_billing ) {- echo ' class="fs-read-mode"';- } ?>>- <tr>- <td><label><span><?php fs_esc_html_echo_inline( 'Business name', 'business-name', $slug ) ?>:</span> <input id="business_name" value="<?php echo esc_attr( $billing->business_name ) ?>" placeholder="<?php fs_esc_attr_echo_inline( 'Business name', 'business-name', $slug ) ?>"></label></td>- <td><label><span><?php fs_esc_html_echo_inline( 'Tax / VAT ID', 'tax-vat-id', $slug ) ?>:</span> <input id="tax_id" value="<?php echo esc_attr( $billing->tax_id ) ?>" placeholder="<?php fs_esc_attr_echo_inline( 'Tax / VAT ID', 'tax-vat-id', $slug ) ?>"></label></td>- </tr>- <tr>- <td><label><span><?php printf( fs_esc_html_inline( 'Address Line %d', 'address-line-n', $slug ), 1 ) ?>:</span> <input id="address_street" value="<?php echo esc_attr( $billing->address_street ) ?>" placeholder="<?php printf( fs_esc_attr_inline( 'Address Line %d', 'address-line-n', $slug ), 1 ) ?>"></label></td>- <td><label><span><?php printf( fs_esc_html_inline( 'Address Line %d', 'address-line-n', $slug ), 2 ) ?>:</span> <input id="address_apt" value="<?php echo esc_attr( $billing->address_apt ) ?>" placeholder="<?php printf( fs_esc_attr_inline( 'Address Line %d', 'address-line-n', $slug ), 2 ) ?>"></label></td>- </tr>- <tr>- <td><label><span><?php fs_esc_html_echo_inline( 'City', 'city', $slug ) ?> / <?php fs_esc_html_echo_inline( 'Town', 'town', $slug ) ?>:</span> <input id="address_city" value="<?php echo esc_attr( $billing->address_city ) ?>" placeholder="<?php fs_esc_attr_echo_inline( 'City', 'city', $slug ) ?> / <?php fs_esc_attr_echo_inline( 'Town', 'town', $slug ) ?>"></label></td>- <td><label><span><?php fs_esc_html_echo_inline( 'ZIP / Postal Code', 'zip-postal-code', $slug ) ?>:</span> <input id="address_zip" value="<?php echo esc_attr( $billing->address_zip ) ?>" placeholder="<?php fs_esc_attr_echo_inline( 'ZIP / Postal Code', 'zip-postal-code', $slug ) ?>"></label></td>- </tr>- <tr>- <?php $countries = array(- 'AF' => 'Afghanistan',- 'AX' => 'Aland Islands',- 'AL' => 'Albania',- 'DZ' => 'Algeria',- 'AS' => 'American Samoa',- 'AD' => 'Andorra',- 'AO' => 'Angola',- 'AI' => 'Anguilla',- 'AQ' => 'Antarctica',- 'AG' => 'Antigua and Barbuda',- 'AR' => 'Argentina',- 'AM' => 'Armenia',- 'AW' => 'Aruba',- 'AU' => 'Australia',- 'AT' => 'Austria',- 'AZ' => 'Azerbaijan',- 'BS' => 'Bahamas',- 'BH' => 'Bahrain',- 'BD' => 'Bangladesh',- 'BB' => 'Barbados',- 'BY' => 'Belarus',- 'BE' => 'Belgium',- 'BZ' => 'Belize',- 'BJ' => 'Benin',- 'BM' => 'Bermuda',- 'BT' => 'Bhutan',- 'BO' => 'Bolivia',- 'BQ' => 'Bonaire, Saint Eustatius and Saba',- 'BA' => 'Bosnia and Herzegovina',- 'BW' => 'Botswana',- 'BV' => 'Bouvet Island',- 'BR' => 'Brazil',- 'IO' => 'British Indian Ocean Territory',- 'VG' => 'British Virgin Islands',- 'BN' => 'Brunei',- 'BG' => 'Bulgaria',- 'BF' => 'Burkina Faso',- 'BI' => 'Burundi',- 'KH' => 'Cambodia',- 'CM' => 'Cameroon',- 'CA' => 'Canada',- 'CV' => 'Cape Verde',- 'KY' => 'Cayman Islands',- 'CF' => 'Central African Republic',- 'TD' => 'Chad',- 'CL' => 'Chile',- 'CN' => 'China',- 'CX' => 'Christmas Island',- 'CC' => 'Cocos Islands',- 'CO' => 'Colombia',- 'KM' => 'Comoros',- 'CK' => 'Cook Islands',- 'CR' => 'Costa Rica',- 'HR' => 'Croatia',- 'CU' => 'Cuba',- 'CW' => 'Curacao',- 'CY' => 'Cyprus',- 'CZ' => 'Czech Republic',- 'CD' => 'Democratic Republic of the Congo',- 'DK' => 'Denmark',- 'DJ' => 'Djibouti',- 'DM' => 'Dominica',- 'DO' => 'Dominican Republic',- 'TL' => 'East Timor',- 'EC' => 'Ecuador',- 'EG' => 'Egypt',- 'SV' => 'El Salvador',- 'GQ' => 'Equatorial Guinea',- 'ER' => 'Eritrea',- 'EE' => 'Estonia',- 'ET' => 'Ethiopia',- 'FK' => 'Falkland Islands',- 'FO' => 'Faroe Islands',- 'FJ' => 'Fiji',- 'FI' => 'Finland',- 'FR' => 'France',- 'GF' => 'French Guiana',- 'PF' => 'French Polynesia',- 'TF' => 'French Southern Territories',- 'GA' => 'Gabon',- 'GM' => 'Gambia',- 'GE' => 'Georgia',- 'DE' => 'Germany',- 'GH' => 'Ghana',- 'GI' => 'Gibraltar',- 'GR' => 'Greece',- 'GL' => 'Greenland',- 'GD' => 'Grenada',- 'GP' => 'Guadeloupe',- 'GU' => 'Guam',- 'GT' => 'Guatemala',- 'GG' => 'Guernsey',- 'GN' => 'Guinea',- 'GW' => 'Guinea-Bissau',- 'GY' => 'Guyana',- 'HT' => 'Haiti',- 'HM' => 'Heard Island and McDonald Islands',- 'HN' => 'Honduras',- 'HK' => 'Hong Kong',- 'HU' => 'Hungary',- 'IS' => 'Iceland',- 'IN' => 'India',- 'ID' => 'Indonesia',- 'IR' => 'Iran',- 'IQ' => 'Iraq',- 'IE' => 'Ireland',- 'IM' => 'Isle of Man',- 'IL' => 'Israel',- 'IT' => 'Italy',- 'CI' => 'Ivory Coast',- 'JM' => 'Jamaica',- 'JP' => 'Japan',- 'JE' => 'Jersey',- 'JO' => 'Jordan',- 'KZ' => 'Kazakhstan',- 'KE' => 'Kenya',- 'KI' => 'Kiribati',- 'XK' => 'Kosovo',- 'KW' => 'Kuwait',- 'KG' => 'Kyrgyzstan',- 'LA' => 'Laos',- 'LV' => 'Latvia',- 'LB' => 'Lebanon',- 'LS' => 'Lesotho',- 'LR' => 'Liberia',- 'LY' => 'Libya',- 'LI' => 'Liechtenstein',- 'LT' => 'Lithuania',- 'LU' => 'Luxembourg',- 'MO' => 'Macao',- 'MK' => 'Macedonia',- 'MG' => 'Madagascar',- 'MW' => 'Malawi',- 'MY' => 'Malaysia',- 'MV' => 'Maldives',- 'ML' => 'Mali',- 'MT' => 'Malta',- 'MH' => 'Marshall Islands',- 'MQ' => 'Martinique',- 'MR' => 'Mauritania',- 'MU' => 'Mauritius',- 'YT' => 'Mayotte',- 'MX' => 'Mexico',- 'FM' => 'Micronesia',- 'MD' => 'Moldova',- 'MC' => 'Monaco',- 'MN' => 'Mongolia',- 'ME' => 'Montenegro',- 'MS' => 'Montserrat',- 'MA' => 'Morocco',- 'MZ' => 'Mozambique',- 'MM' => 'Myanmar',- 'NA' => 'Namibia',- 'NR' => 'Nauru',- 'NP' => 'Nepal',- 'NL' => 'Netherlands',- 'NC' => 'New Caledonia',- 'NZ' => 'New Zealand',- 'NI' => 'Nicaragua',- 'NE' => 'Niger',- 'NG' => 'Nigeria',- 'NU' => 'Niue',- 'NF' => 'Norfolk Island',- 'KP' => 'North Korea',- 'MP' => 'Northern Mariana Islands',- 'NO' => 'Norway',- 'OM' => 'Oman',- 'PK' => 'Pakistan',- 'PW' => 'Palau',- 'PS' => 'Palestinian Territory',- 'PA' => 'Panama',- 'PG' => 'Papua New Guinea',- 'PY' => 'Paraguay',- 'PE' => 'Peru',- 'PH' => 'Philippines',- 'PN' => 'Pitcairn',- 'PL' => 'Poland',- 'PT' => 'Portugal',- 'PR' => 'Puerto Rico',- 'QA' => 'Qatar',- 'CG' => 'Republic of the Congo',- 'RE' => 'Reunion',- 'RO' => 'Romania',- 'RU' => 'Russia',- 'RW' => 'Rwanda',- 'BL' => 'Saint Barthelemy',- 'SH' => 'Saint Helena',- 'KN' => 'Saint Kitts and Nevis',- 'LC' => 'Saint Lucia',- 'MF' => 'Saint Martin',- 'PM' => 'Saint Pierre and Miquelon',- 'VC' => 'Saint Vincent and the Grenadines',- 'WS' => 'Samoa',- 'SM' => 'San Marino',- 'ST' => 'Sao Tome and Principe',- 'SA' => 'Saudi Arabia',- 'SN' => 'Senegal',- 'RS' => 'Serbia',- 'SC' => 'Seychelles',- 'SL' => 'Sierra Leone',- 'SG' => 'Singapore',- 'SX' => 'Sint Maarten',- 'SK' => 'Slovakia',- 'SI' => 'Slovenia',- 'SB' => 'Solomon Islands',- 'SO' => 'Somalia',- 'ZA' => 'South Africa',- 'GS' => 'South Georgia and the South Sandwich Islands',- 'KR' => 'South Korea',- 'SS' => 'South Sudan',- 'ES' => 'Spain',- 'LK' => 'Sri Lanka',- 'SD' => 'Sudan',- 'SR' => 'Suriname',- 'SJ' => 'Svalbard and Jan Mayen',- 'SZ' => 'Swaziland',- 'SE' => 'Sweden',- 'CH' => 'Switzerland',- 'SY' => 'Syria',- 'TW' => 'Taiwan',- 'TJ' => 'Tajikistan',- 'TZ' => 'Tanzania',- 'TH' => 'Thailand',- 'TG' => 'Togo',- 'TK' => 'Tokelau',- 'TO' => 'Tonga',- 'TT' => 'Trinidad and Tobago',- 'TN' => 'Tunisia',- 'TR' => 'Turkey',- 'TM' => 'Turkmenistan',- 'TC' => 'Turks and Caicos Islands',- 'TV' => 'Tuvalu',- 'VI' => 'U.S. Virgin Islands',- 'UG' => 'Uganda',- 'UA' => 'Ukraine',- 'AE' => 'United Arab Emirates',- 'GB' => 'United Kingdom',- 'US' => 'United States',- 'UM' => 'United States Minor Outlying Islands',- 'UY' => 'Uruguay',- 'UZ' => 'Uzbekistan',- 'VU' => 'Vanuatu',- 'VA' => 'Vatican',- 'VE' => 'Venezuela',- 'VN' => 'Vietnam',- 'WF' => 'Wallis and Futuna',- 'EH' => 'Western Sahara',- 'YE' => 'Yemen',- 'ZM' => 'Zambia',- 'ZW' => 'Zimbabwe',- ) ?>- <td><label><span><?php fs_esc_html_echo_inline( 'Country', 'country', $slug ) ?>:</span> <select id="address_country_code">- <?php if ( empty( $billing->address_country_code ) ) : ?>- <option value="" selected><?php fs_esc_html_echo_inline( 'Select Country', 'select-country', $slug ) ?></option>- <?php endif ?>- <?php foreach ( $countries as $code => $country ) : ?>- <option- value="<?php echo esc_attr( $code ) ?>" <?php selected( $billing->address_country_code, $code ) ?>><?php echo esc_html( $country ) ?></option>- <?php endforeach ?>- </select></label></td>- <td><label><span><?php fs_esc_html_echo_inline( 'State', 'state', $slug ) ?> / <?php fs_esc_html_echo_inline( 'Province', 'province', $slug ) ?>:</span>- <input id="address_state" value="<?php echo esc_attr( $billing->address_state ) ?>" placeholder="<?php fs_esc_html_echo_inline( 'State', 'state', $slug ) ?> / <?php fs_esc_html_echo_inline( 'Province', 'province', $slug ) ?>"></label></td>- </tr>- <tr>- <td colspan="2">- <button- class="button"><?php echo esc_html( $has_billing ?- $edit_text :- $update_text- ) ?></button>- </td>- </tr>- </table>- </div>-</div>-<!--/ Billing -->-<script type="text/javascript">- (function($){- var $billingAddress = $('#fs_billing_address'),- $billingInputs = $billingAddress.find('input, select');-- var setPrevValues = function () {- $billingInputs.each(function () {- $(this).attr('data-val', $(this).val());- });- };-- setPrevValues();-- var hasBillingChanged = function () {- for (var i = 0, len = $billingInputs.length; i < len; i++){- var $this = $($billingInputs[i]);- if ($this.attr('data-val') !== $this.val()) {- return true;- }- }-- return false;- };-- var isEditAllFieldsMode = false;-- $billingAddress.find('.button').click(function(){- $billingAddress.toggleClass('fs-read-mode');-- var isEditMode = !$billingAddress.hasClass('fs-read-mode');-- $(this)- .html(isEditMode ? '<?php echo esc_js( $update_text ) ?>' : '<?php echo esc_js( $edit_text ) ?>')- .toggleClass('button-primary');-- if (isEditMode) {- $('#business_name').focus().select();- isEditAllFieldsMode = true;- } else {- isEditAllFieldsMode = false;-- if (!hasBillingChanged())- return;-- var billing = {};-- $billingInputs.each(function(){- if ($(this).attr('data-val') !== $(this).val()) {- billing[$(this).attr('id')] = $(this).val();- }- });-- $.ajax({- url : <?php echo Freemius::ajax_url() ?>,- method : 'POST',- data : {- action : <?php echo wp_json_encode( $fs->get_ajax_action( 'update_billing' ) ) ?>,- security : <?php echo wp_json_encode( $fs->get_ajax_security( 'update_billing' ) ) ?>,- module_id: <?php echo wp_json_encode( $fs->get_id() ) ?>,- billing : billing- },- success: function (resultObj) {- if (resultObj.success) {- setPrevValues();- } else {- alert(resultObj.error);- }- }- });- }- });-- $billingInputs- // Get into edit mode upon selection.- .focus(function () {- var isEditMode = !$billingAddress.hasClass('fs-read-mode');-- if (isEditMode) {- return;- }-- $billingAddress.toggleClass('fs-read-mode');- $billingAddress.find('.button')- .html('<?php echo esc_js( $update_text ) ?>')- .toggleClass('button-primary');- })- // If blured after editing only one field without changes, exit edit mode.- .blur(function () {- if (!isEditAllFieldsMode && !hasBillingChanged()) {- $billingAddress.toggleClass('fs-read-mode');- $billingAddress.find('.button')- .html('<?php echo esc_js( $edit_text ) ?>')- .toggleClass('button-primary');- }- });- })(jQuery);+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2016, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + + $slug = $fs->get_slug(); + + $edit_text = fs_text_x_inline( 'Edit', 'verb', 'edit', $slug ); + $update_text = fs_text_x_inline( 'Update', 'verb', 'update', $slug ); + + $billing = $fs->_fetch_billing(); + $has_billing = ( $billing instanceof FS_Billing ); + if ( ! $has_billing ) { + $billing = new FS_Billing(); + } +?> +<!-- Billing --> +<div class="postbox"> + <div id="fs_billing"> + <h3><span class="dashicons dashicons-portfolio"></span> <?php fs_esc_html_echo_inline( 'Billing', 'billing', $slug ) ?></h3> + <table id="fs_billing_address"<?php if ( $has_billing ) { + echo ' class="fs-read-mode"'; + } ?>> + <tr> + <td><label><span><?php fs_esc_html_echo_inline( 'Business name', 'business-name', $slug ) ?>:</span> <input id="business_name" value="<?php echo esc_attr( $billing->business_name ) ?>" placeholder="<?php fs_esc_attr_echo_inline( 'Business name', 'business-name', $slug ) ?>"></label></td> + <td><label><span><?php fs_esc_html_echo_inline( 'Tax / VAT ID', 'tax-vat-id', $slug ) ?>:</span> <input id="tax_id" value="<?php echo esc_attr( $billing->tax_id ) ?>" placeholder="<?php fs_esc_attr_echo_inline( 'Tax / VAT ID', 'tax-vat-id', $slug ) ?>"></label></td> + </tr> + <tr> + <td><label><span><?php printf( fs_esc_html_inline( 'Address Line %d', 'address-line-n', $slug ), 1 ) ?>:</span> <input id="address_street" value="<?php echo esc_attr( $billing->address_street ) ?>" placeholder="<?php printf( fs_esc_attr_inline( 'Address Line %d', 'address-line-n', $slug ), 1 ) ?>"></label></td> + <td><label><span><?php printf( fs_esc_html_inline( 'Address Line %d', 'address-line-n', $slug ), 2 ) ?>:</span> <input id="address_apt" value="<?php echo esc_attr( $billing->address_apt ) ?>" placeholder="<?php printf( fs_esc_attr_inline( 'Address Line %d', 'address-line-n', $slug ), 2 ) ?>"></label></td> + </tr> + <tr> + <td><label><span><?php fs_esc_html_echo_inline( 'City', 'city', $slug ) ?> / <?php fs_esc_html_echo_inline( 'Town', 'town', $slug ) ?>:</span> <input id="address_city" value="<?php echo esc_attr( $billing->address_city ) ?>" placeholder="<?php fs_esc_attr_echo_inline( 'City', 'city', $slug ) ?> / <?php fs_esc_attr_echo_inline( 'Town', 'town', $slug ) ?>"></label></td> + <td><label><span><?php fs_esc_html_echo_inline( 'ZIP / Postal Code', 'zip-postal-code', $slug ) ?>:</span> <input id="address_zip" value="<?php echo esc_attr( $billing->address_zip ) ?>" placeholder="<?php fs_esc_attr_echo_inline( 'ZIP / Postal Code', 'zip-postal-code', $slug ) ?>"></label></td> + </tr> + <tr> + <?php $countries = array( + 'AF' => 'Afghanistan', + 'AX' => 'Aland Islands', + 'AL' => 'Albania', + 'DZ' => 'Algeria', + 'AS' => 'American Samoa', + 'AD' => 'Andorra', + 'AO' => 'Angola', + 'AI' => 'Anguilla', + 'AQ' => 'Antarctica', + 'AG' => 'Antigua and Barbuda', + 'AR' => 'Argentina', + 'AM' => 'Armenia', + 'AW' => 'Aruba', + 'AU' => 'Australia', + 'AT' => 'Austria', + 'AZ' => 'Azerbaijan', + 'BS' => 'Bahamas', + 'BH' => 'Bahrain', + 'BD' => 'Bangladesh', + 'BB' => 'Barbados', + 'BY' => 'Belarus', + 'BE' => 'Belgium', + 'BZ' => 'Belize', + 'BJ' => 'Benin', + 'BM' => 'Bermuda', + 'BT' => 'Bhutan', + 'BO' => 'Bolivia', + 'BQ' => 'Bonaire, Saint Eustatius and Saba', + 'BA' => 'Bosnia and Herzegovina', + 'BW' => 'Botswana', + 'BV' => 'Bouvet Island', + 'BR' => 'Brazil', + 'IO' => 'British Indian Ocean Territory', + 'VG' => 'British Virgin Islands', + 'BN' => 'Brunei', + 'BG' => 'Bulgaria', + 'BF' => 'Burkina Faso', + 'BI' => 'Burundi', + 'KH' => 'Cambodia', + 'CM' => 'Cameroon', + 'CA' => 'Canada', + 'CV' => 'Cape Verde', + 'KY' => 'Cayman Islands', + 'CF' => 'Central African Republic', + 'TD' => 'Chad', + 'CL' => 'Chile', + 'CN' => 'China', + 'CX' => 'Christmas Island', + 'CC' => 'Cocos Islands', + 'CO' => 'Colombia', + 'KM' => 'Comoros', + 'CK' => 'Cook Islands', + 'CR' => 'Costa Rica', + 'HR' => 'Croatia', + 'CU' => 'Cuba', + 'CW' => 'Curacao', + 'CY' => 'Cyprus', + 'CZ' => 'Czech Republic', + 'CD' => 'Democratic Republic of the Congo', + 'DK' => 'Denmark', + 'DJ' => 'Djibouti', + 'DM' => 'Dominica', + 'DO' => 'Dominican Republic', + 'TL' => 'East Timor', + 'EC' => 'Ecuador', + 'EG' => 'Egypt', + 'SV' => 'El Salvador', + 'GQ' => 'Equatorial Guinea', + 'ER' => 'Eritrea', + 'EE' => 'Estonia', + 'ET' => 'Ethiopia', + 'FK' => 'Falkland Islands', + 'FO' => 'Faroe Islands', + 'FJ' => 'Fiji', + 'FI' => 'Finland', + 'FR' => 'France', + 'GF' => 'French Guiana', + 'PF' => 'French Polynesia', + 'TF' => 'French Southern Territories', + 'GA' => 'Gabon', + 'GM' => 'Gambia', + 'GE' => 'Georgia', + 'DE' => 'Germany', + 'GH' => 'Ghana', + 'GI' => 'Gibraltar', + 'GR' => 'Greece', + 'GL' => 'Greenland', + 'GD' => 'Grenada', + 'GP' => 'Guadeloupe', + 'GU' => 'Guam', + 'GT' => 'Guatemala', + 'GG' => 'Guernsey', + 'GN' => 'Guinea', + 'GW' => 'Guinea-Bissau', + 'GY' => 'Guyana', + 'HT' => 'Haiti', + 'HM' => 'Heard Island and McDonald Islands', + 'HN' => 'Honduras', + 'HK' => 'Hong Kong', + 'HU' => 'Hungary', + 'IS' => 'Iceland', + 'IN' => 'India', + 'ID' => 'Indonesia', + 'IR' => 'Iran', + 'IQ' => 'Iraq', + 'IE' => 'Ireland', + 'IM' => 'Isle of Man', + 'IL' => 'Israel', + 'IT' => 'Italy', + 'CI' => 'Ivory Coast', + 'JM' => 'Jamaica', + 'JP' => 'Japan', + 'JE' => 'Jersey', + 'JO' => 'Jordan', + 'KZ' => 'Kazakhstan', + 'KE' => 'Kenya', + 'KI' => 'Kiribati', + 'XK' => 'Kosovo', + 'KW' => 'Kuwait', + 'KG' => 'Kyrgyzstan', + 'LA' => 'Laos', + 'LV' => 'Latvia', + 'LB' => 'Lebanon', + 'LS' => 'Lesotho', + 'LR' => 'Liberia', + 'LY' => 'Libya', + 'LI' => 'Liechtenstein', + 'LT' => 'Lithuania', + 'LU' => 'Luxembourg', + 'MO' => 'Macao', + 'MK' => 'Macedonia', + 'MG' => 'Madagascar', + 'MW' => 'Malawi', + 'MY' => 'Malaysia', + 'MV' => 'Maldives', + 'ML' => 'Mali', + 'MT' => 'Malta', + 'MH' => 'Marshall Islands', + 'MQ' => 'Martinique', + 'MR' => 'Mauritania', + 'MU' => 'Mauritius', + 'YT' => 'Mayotte', + 'MX' => 'Mexico', + 'FM' => 'Micronesia', + 'MD' => 'Moldova', + 'MC' => 'Monaco', + 'MN' => 'Mongolia', + 'ME' => 'Montenegro', + 'MS' => 'Montserrat', + 'MA' => 'Morocco', + 'MZ' => 'Mozambique', + 'MM' => 'Myanmar', + 'NA' => 'Namibia', + 'NR' => 'Nauru', + 'NP' => 'Nepal', + 'NL' => 'Netherlands', + 'NC' => 'New Caledonia', + 'NZ' => 'New Zealand', + 'NI' => 'Nicaragua', + 'NE' => 'Niger', + 'NG' => 'Nigeria', + 'NU' => 'Niue', + 'NF' => 'Norfolk Island', + 'KP' => 'North Korea', + 'MP' => 'Northern Mariana Islands', + 'NO' => 'Norway', + 'OM' => 'Oman', + 'PK' => 'Pakistan', + 'PW' => 'Palau', + 'PS' => 'Palestinian Territory', + 'PA' => 'Panama', + 'PG' => 'Papua New Guinea', + 'PY' => 'Paraguay', + 'PE' => 'Peru', + 'PH' => 'Philippines', + 'PN' => 'Pitcairn', + 'PL' => 'Poland', + 'PT' => 'Portugal', + 'PR' => 'Puerto Rico', + 'QA' => 'Qatar', + 'CG' => 'Republic of the Congo', + 'RE' => 'Reunion', + 'RO' => 'Romania', + 'RU' => 'Russia', + 'RW' => 'Rwanda', + 'BL' => 'Saint Barthelemy', + 'SH' => 'Saint Helena', + 'KN' => 'Saint Kitts and Nevis', + 'LC' => 'Saint Lucia', + 'MF' => 'Saint Martin', + 'PM' => 'Saint Pierre and Miquelon', + 'VC' => 'Saint Vincent and the Grenadines', + 'WS' => 'Samoa', + 'SM' => 'San Marino', + 'ST' => 'Sao Tome and Principe', + 'SA' => 'Saudi Arabia', + 'SN' => 'Senegal', + 'RS' => 'Serbia', + 'SC' => 'Seychelles', + 'SL' => 'Sierra Leone', + 'SG' => 'Singapore', + 'SX' => 'Sint Maarten', + 'SK' => 'Slovakia', + 'SI' => 'Slovenia', + 'SB' => 'Solomon Islands', + 'SO' => 'Somalia', + 'ZA' => 'South Africa', + 'GS' => 'South Georgia and the South Sandwich Islands', + 'KR' => 'South Korea', + 'SS' => 'South Sudan', + 'ES' => 'Spain', + 'LK' => 'Sri Lanka', + 'SD' => 'Sudan', + 'SR' => 'Suriname', + 'SJ' => 'Svalbard and Jan Mayen', + 'SZ' => 'Swaziland', + 'SE' => 'Sweden', + 'CH' => 'Switzerland', + 'SY' => 'Syria', + 'TW' => 'Taiwan', + 'TJ' => 'Tajikistan', + 'TZ' => 'Tanzania', + 'TH' => 'Thailand', + 'TG' => 'Togo', + 'TK' => 'Tokelau', + 'TO' => 'Tonga', + 'TT' => 'Trinidad and Tobago', + 'TN' => 'Tunisia', + 'TR' => 'Turkey', + 'TM' => 'Turkmenistan', + 'TC' => 'Turks and Caicos Islands', + 'TV' => 'Tuvalu', + 'VI' => 'U.S. Virgin Islands', + 'UG' => 'Uganda', + 'UA' => 'Ukraine', + 'AE' => 'United Arab Emirates', + 'GB' => 'United Kingdom', + 'US' => 'United States', + 'UM' => 'United States Minor Outlying Islands', + 'UY' => 'Uruguay', + 'UZ' => 'Uzbekistan', + 'VU' => 'Vanuatu', + 'VA' => 'Vatican', + 'VE' => 'Venezuela', + 'VN' => 'Vietnam', + 'WF' => 'Wallis and Futuna', + 'EH' => 'Western Sahara', + 'YE' => 'Yemen', + 'ZM' => 'Zambia', + 'ZW' => 'Zimbabwe', + ) ?> + <td><label><span><?php fs_esc_html_echo_inline( 'Country', 'country', $slug ) ?>:</span> <select id="address_country_code"> + <?php if ( empty( $billing->address_country_code ) ) : ?> + <option value="" selected><?php fs_esc_html_echo_inline( 'Select Country', 'select-country', $slug ) ?></option> + <?php endif ?> + <?php foreach ( $countries as $code => $country ) : ?> + <option + value="<?php echo esc_attr( $code ) ?>" <?php selected( $billing->address_country_code, $code ) ?>><?php echo esc_html( $country ) ?></option> + <?php endforeach ?> + </select></label></td> + <td><label><span><?php fs_esc_html_echo_inline( 'State', 'state', $slug ) ?> / <?php fs_esc_html_echo_inline( 'Province', 'province', $slug ) ?>:</span> + <input id="address_state" value="<?php echo esc_attr( $billing->address_state ) ?>" placeholder="<?php fs_esc_html_echo_inline( 'State', 'state', $slug ) ?> / <?php fs_esc_html_echo_inline( 'Province', 'province', $slug ) ?>"></label></td> + </tr> + <tr> + <td colspan="2"> + <button + class="button"><?php echo esc_html( $has_billing ? + $edit_text : + $update_text + ) ?></button> + </td> + </tr> + </table> + </div> +</div> +<!--/ Billing --> +<script type="text/javascript"> + (function($){ + var $billingAddress = $('#fs_billing_address'), + $billingInputs = $billingAddress.find('input, select'); + + var setPrevValues = function () { + $billingInputs.each(function () { + $(this).attr('data-val', $(this).val()); + }); + }; + + setPrevValues(); + + var hasBillingChanged = function () { + for (var i = 0, len = $billingInputs.length; i < len; i++){ + var $this = $($billingInputs[i]); + if ($this.attr('data-val') !== $this.val()) { + return true; + } + } + + return false; + }; + + var isEditAllFieldsMode = false; + + $billingAddress.find('.button').click(function(){ + $billingAddress.toggleClass('fs-read-mode'); + + var isEditMode = !$billingAddress.hasClass('fs-read-mode'); + + $(this) + .html(isEditMode ? '<?php echo esc_js( $update_text ) ?>' : '<?php echo esc_js( $edit_text ) ?>') + .toggleClass('button-primary'); + + if (isEditMode) { + $('#business_name').focus().select(); + isEditAllFieldsMode = true; + } else { + isEditAllFieldsMode = false; + + if (!hasBillingChanged()) + return; + + var billing = {}; + + $billingInputs.each(function(){ + if ($(this).attr('data-val') !== $(this).val()) { + billing[$(this).attr('id')] = $(this).val(); + } + }); + + $.ajax({ + url : <?php echo Freemius::ajax_url() ?>, + method : 'POST', + data : { + action : <?php echo wp_json_encode( $fs->get_ajax_action( 'update_billing' ) ) ?>, + security : <?php echo wp_json_encode( $fs->get_ajax_security( 'update_billing' ) ) ?>, + module_id: <?php echo wp_json_encode( $fs->get_id() ) ?>, + billing : billing + }, + success: function (resultObj) { + if (resultObj.success) { + setPrevValues(); + } else { + alert(resultObj.error); + } + } + }); + } + }); + + $billingInputs + // Get into edit mode upon selection. + .focus(function () { + var isEditMode = !$billingAddress.hasClass('fs-read-mode'); + + if (isEditMode) { + return; + } + + $billingAddress.toggleClass('fs-read-mode'); + $billingAddress.find('.button') + .html('<?php echo esc_js( $update_text ) ?>') + .toggleClass('button-primary'); + }) + // If blured after editing only one field without changes, exit edit mode. + .blur(function () { + if (!isEditAllFieldsMode && !hasBillingChanged()) { + $billingAddress.toggleClass('fs-read-mode'); + $billingAddress.find('.button') + .html('<?php echo esc_js( $edit_text ) ?>') + .toggleClass('button-primary'); + } + }); + })(jQuery); </script>\ No newline at end of file
# Security Analysis: Code Diff Review After analyzing the provided diff for `inc/freemius/templates/account/billing.php`, here is my assessment: Vulnerability Existed: no This diff contains only **line ending changes** (CRLF to LF conversion). There are no functional code modifications, no new code additions, and no alterations to existing logic. **Analysis Details:** - **Old Code**: Lines ending with Windows-style line endings (CRLF - `\r\n`) - **Fixed Code**: Lines ending with Unix-style line endings (LF - `\n`) The actual code content remains identical across all 423 lines. The diff shows a purely cosmetic change related to file formatting/line endings, which has no security implications. **Security Assessment:** - No input validation changes - No sanitization modifications - No escaping function updates - No authentication/authorization changes - No logic flow alterations - No vulnerability fixes or regressions This is a non-security formatting adjustment typically made for cross-platform consistency or to comply with project coding standards.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/account/index.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/account/index.php 2026-01-19 00:17:37.671046273 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Vulnerability Identified - File Structure Protection Maintained Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff represents only whitespace/formatting changes (likely line ending normalization from CRLF to LF or similar). The file content remains functionally identical. The file itself is a security-appropriate blank index.php file designed to prevent directory listing and hide file structure, which is a standard security practice. No actual code changes have been made, and no vulnerabilities have been introduced or fixed. The file continues to serve its intended purpose of preventing direct access and information disclosure through directory traversal.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/account/partials/activate-license-button.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/account/partials/activate-license-button.php 2026-01-19 00:17:37.671046273 +0000@@ -1,54 +1,54 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.0.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- * @var FS_Plugin_License $available_license- * @var string $slug- */- $fs = $VARS['freemius'];- $available_license = $VARS['license'];- $premium_plan = $VARS['plan'];- $slug = $VARS['slug'];-- $blog_id = ! empty( $VARS['blog_id'] ) && is_numeric( $VARS['blog_id'] ) ?- $VARS['blog_id'] :- '';- $install_id = ! empty( $VARS['install_id'] ) && FS_Site::is_valid_id( $VARS['install_id'] ) ?- $VARS['install_id'] :- '';-- $activate_plan_text = fs_text_inline( 'Activate %s Plan', 'activate-x-plan', $slug );-- $action = 'activate_license';-?>-<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">- <input type="hidden" name="fs_action" value="<?php echo $action ?>">- <?php wp_nonce_field( trim("{$action}:{$blog_id}:{$install_id}", ':') ) ?>- <input type="hidden" name="install_id" value="<?php echo $install_id ?>">- <input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">- <input type="hidden" name="license_id" value="<?php echo $available_license->id ?>">- <input type="submit" class="fs-activate-license button<?php echo ! empty( $VARS['class'] ) ? ' ' . $VARS['class'] : '' ?>"- value="<?php echo esc_attr( sprintf(- $activate_plan_text . '%s',- $premium_plan->title,- ( $VARS['is_localhost'] && $available_license->is_free_localhost ) ?- ' [' . fs_text_inline( 'Localhost', 'localhost', $slug ) . ']' :- ( $available_license->is_single_site() ?- '' :- ' [' . ( 1 < $available_license->left() ?- sprintf( fs_text_x_inline( '%s left', 'as 5 licenses left', 'x-left', $slug ), $available_license->left() ) :- strtolower( fs_text_inline( 'Last license', 'last-license', $slug ) ) ) . ']'- )- ) ) ?> ">+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.0.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + * @var FS_Plugin_License $available_license + * @var string $slug + */ + $fs = $VARS['freemius']; + $available_license = $VARS['license']; + $premium_plan = $VARS['plan']; + $slug = $VARS['slug']; + + $blog_id = ! empty( $VARS['blog_id'] ) && is_numeric( $VARS['blog_id'] ) ? + $VARS['blog_id'] : + ''; + $install_id = ! empty( $VARS['install_id'] ) && FS_Site::is_valid_id( $VARS['install_id'] ) ? + $VARS['install_id'] : + ''; + + $activate_plan_text = fs_text_inline( 'Activate %s Plan', 'activate-x-plan', $slug ); + + $action = 'activate_license'; +?> +<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST"> + <input type="hidden" name="fs_action" value="<?php echo $action ?>"> + <?php wp_nonce_field( trim("{$action}:{$blog_id}:{$install_id}", ':') ) ?> + <input type="hidden" name="install_id" value="<?php echo $install_id ?>"> + <input type="hidden" name="blog_id" value="<?php echo $blog_id ?>"> + <input type="hidden" name="license_id" value="<?php echo $available_license->id ?>"> + <input type="submit" class="fs-activate-license button<?php echo ! empty( $VARS['class'] ) ? ' ' . $VARS['class'] : '' ?>" + value="<?php echo esc_attr( sprintf( + $activate_plan_text . '%s', + $premium_plan->title, + ( $VARS['is_localhost'] && $available_license->is_free_localhost ) ? + ' [' . fs_text_inline( 'Localhost', 'localhost', $slug ) . ']' : + ( $available_license->is_single_site() ? + '' : + ' [' . ( 1 < $available_license->left() ? + sprintf( fs_text_x_inline( '%s left', 'as 5 licenses left', 'x-left', $slug ), $available_license->left() ) : + strtolower( fs_text_inline( 'Last license', 'last-license', $slug ) ) ) . ']' + ) + ) ) ?> "> </form>\ No newline at end of file
Vulnerability Existed: no No Security Vulnerabilities Identified - inc/freemius/templates/account/partials/activate-license-button.php Explanation: The diff shows only line ending changes (CRLF to LF conversion) with no modifications to the actual code logic or content. The file contains: 1. **Proper Output Escaping**: The `esc_attr()` function is used on line 44 to escape the submit button value, preventing XSS attacks. 2. **Nonce Verification**: Line 37 uses `wp_nonce_field()` to generate a nonce for CSRF protection on the form submission. 3. **Input Validation**: Lines 25-29 validate `$blog_id` (numeric check) and `$install_id` (using `FS_Site::is_valid_id()`) before use. 4. **Safe Template Variables**: The code uses properly-escaped WordPress functions like `fs_text_inline()` and `fs_text_x_inline()` which are designed to safely handle translatable strings. 5. **No Database Operations**: The template contains no direct database queries or dynamic SQL that could be vulnerable to injection. The only change in this diff is whitespace/line ending normalization, which does not affect security posture. All security controls that were present before remain in place.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/account/partials/deactivate-license-button.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/account/partials/deactivate-license-button.php 2026-01-19 00:17:37.671046273 +0000@@ -1,36 +1,36 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.0.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- * @var string $slug- */- $slug = $VARS['slug'];- $fs = $VARS['freemius'];-- $blog_id = ! empty( $VARS['blog_id'] ) && is_numeric( $VARS['blog_id'] ) ?- $VARS['blog_id'] :- '';- $install_id = ! empty( $VARS['install_id'] ) && FS_Site::is_valid_id( $VARS['install_id'] ) ?- $VARS['install_id'] :- '';-- $action = 'deactivate_license';-?>-<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">- <input type="hidden" name="fs_action" value="<?php echo $action ?>">- <?php wp_nonce_field( trim("{$action}:{$blog_id}:{$install_id}", ':') ) ?>- <input type="hidden" name="install_id" value="<?php echo $install_id ?>">- <input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">- <button type="button" class="fs-deactivate-license button<?php echo ! empty( $VARS['class'] ) ? ' ' . $VARS['class'] : '' ?>"><?php fs_echo_inline( 'Deactivate License', 'deactivate-license', $slug ) ?></button>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.0.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + * @var string $slug + */ + $slug = $VARS['slug']; + $fs = $VARS['freemius']; + + $blog_id = ! empty( $VARS['blog_id'] ) && is_numeric( $VARS['blog_id'] ) ? + $VARS['blog_id'] : + ''; + $install_id = ! empty( $VARS['install_id'] ) && FS_Site::is_valid_id( $VARS['install_id'] ) ? + $VARS['install_id'] : + ''; + + $action = 'deactivate_license'; +?> +<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST"> + <input type="hidden" name="fs_action" value="<?php echo $action ?>"> + <?php wp_nonce_field( trim("{$action}:{$blog_id}:{$install_id}", ':') ) ?> + <input type="hidden" name="install_id" value="<?php echo $install_id ?>"> + <input type="hidden" name="blog_id" value="<?php echo $blog_id ?>"> + <button type="button" class="fs-deactivate-license button<?php echo ! empty( $VARS['class'] ) ? ' ' . $VARS['class'] : '' ?>"><?php fs_echo_inline( 'Deactivate License', 'deactivate-license', $slug ) ?></button> </form>\ No newline at end of file
Vulnerability Existed: no
No Security Vulnerability Identified - inc/freemius/templates/account/partials/deactivate-license-button.php
Old Code:
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 2.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* @var array $VARS
* @var Freemius $fs
* @var string $slug
*/
$slug = $VARS['slug'];
$fs = $VARS['freemius'];
$blog_id = ! empty( $VARS['blog_id'] ) && is_numeric( $VARS['blog_id'] ) ?
$VARS['blog_id'] :
'';
$install_id = ! empty( $VARS['install_id'] ) && FS_Site::is_valid_id( $VARS['install_id'] ) ?
$VARS['install_id'] :
'';
$action = 'deactivate_license';
?>
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
<input type="hidden" name="fs_action" value="<?php echo $action ?>">
<?php wp_nonce_field( trim("{$action}:{$blog_id}:{$install_id}", ':') ) ?>
<input type="hidden" name="install_id" value="<?php echo $install_id ?>">
<input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">
<button type="button" class="fs-deactivate-license button<?php echo ! empty( $VARS['class'] ) ? ' ' . $VARS['class'] : '' ?>"><?php fs_echo_inline( 'Deactivate License', 'deactivate-license', $slug ) ?></button>
</form>
```
Fixed Code:
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 2.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* @var array $VARS
* @var Freemius $fs
* @var string $slug
*/
$slug = $VARS['slug'];
$fs = $VARS['freemius'];
$blog_id = ! empty( $VARS['blog_id'] ) && is_numeric( $VARS['blog_id'] ) ?
$VARS['blog_id'] :
'';
$install_id = ! empty( $VARS['install_id'] ) && FS_Site::is_valid_id( $VARS['install_id'] ) ?
$VARS['install_id'] :
'';
$action = 'deactivate_license';
?>
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
<input type="hidden" name="fs_action" value="<?php echo $action ?>">
<?php wp_nonce_field( trim("{$action}:{$blog_id}:{$install_id}", ':') ) ?>
<input type="hidden" name="install_id" value="<?php echo $install_id ?>">
<input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">
<button type="button" class="fs-deactivate-license button<?php echo ! empty( $VARS['class'] ) ? ' ' . $VARS['class'] : '' ?>"><?php fs_echo_inline( 'Deactivate License', 'deactivate-license', $slug ) ?></button>
</form>
```
Explanation:
The diff shows only line ending changes (CRLF to LF conversion) with no substantive code modifications. The code structure, logic, and security controls remain identical. All output is properly escaped through WordPress functions (`$fs->_get_admin_page_url()`, `wp_nonce_field()`, and `fs_echo_inline()`). No security vulnerabilities were introduced or fixed in this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/account/partials/disconnect-button.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/account/partials/disconnect-button.php 2026-01-19 00:17:37.671046273 +0000@@ -1,104 +1,104 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2016, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.5.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = $VARS['freemius'];-- /**- * @var FS_Plugin_License $license- */- $license = $VARS['license'];- /**- * @var FS_Plugin_Plan $license_paid_plan- */- $license_paid_plan = $VARS['license_paid_plan'];-- $license_subscription = ( is_object( $license ) && is_object( $license_paid_plan ) ) ?- $fs->_get_subscription( $license->id ) :- null;-- $has_active_subscription = (- is_object( $license_subscription ) &&- $license_subscription->is_active()- );-- $button_id = "fs_disconnect_button_{$fs->get_id()}";-- $website_link = sprintf( '<a href="#" tabindex="-1">%s</a>', fs_strip_url_protocol( untrailingslashit( Freemius::get_unfiltered_site_url() ) ) );-?>-<script type="text/javascript">- // Wrap in a IFFE to prevent leaking global variables.- ( function( $ ) {- $( document ).ready( function() {- var $modal = $( '#fs_modal_delete_site' );-- $( '#<?php echo $button_id ?>' ).on( 'click', function( e ) {- // Prevent the form being submitted.- e.preventDefault();-- $( document.body ).append( $modal );- $modal.show();- } );-- $modal.on( 'click', '.button-close', function ( evt ) {- $modal.hide();- } );-- $modal.on( 'click', '.button-primary', function ( evt ) {- $( '#<?php echo $button_id ?>' ).closest( 'form' )[0].submit();- } );- } );- } )( jQuery );-</script>-<div id="fs_modal_delete_site" class="fs-modal active" style="display: none">- <div class="fs-modal-dialog">- <div class="fs-modal-header">- <h4><?php echo $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?></h4>- </div>- <div class="fs-modal-body">- <?php if ( ! is_object( $license ) ) : ?>- <p><?php echo- // translators: %1$s is replaced with the website's homepage address, %2$s is replaced with the plugin name.- sprintf( esc_html( $fs->get_text_inline( 'By disconnecting the website, previously shared diagnostic data about %1$s will be deleted and no longer visible to %2$s.', 'disconnect-intro-paid' ) ), $website_link, '<b>' . $fs->get_plugin_title() . '</b>' ) ?></p>- <?php else : ?>- <p><?php echo- // translators: %s is replaced with the website's homepage address.- sprintf( esc_html( $fs->get_text_inline( 'Disconnecting the website will permanently remove %s from your User Dashboard\'s account.', 'disconnect-intro-paid' ) ), $website_link ) ?></p>- <?php endif ?>-- <?php if ( $has_active_subscription ) : ?>- <p><?php echo- // translators: %1$s is replaced by the paid plan name, %2$s is replaced with an anchor link with the text "User Dashboard".- sprintf( esc_html( $fs->get_text_inline( 'If you wish to cancel your %1$s plan\'s subscription instead, please navigate to the %2$s and cancel it there.', 'disconnect-subscription-disclaimer' ) ), $license_paid_plan->title, sprintf( '<a href="https://users.freemius.com" target="_blank" rel="noreferrer noopener nofollow">%s</a>', $fs->get_text_inline( 'User Dashboard', 'user-dashboard' ) )- ) ?></p>- <?php endif ?>-- <p><?php echo esc_html( $fs->get_text_inline( 'Are you sure you would like to proceed with the disconnection?', 'disconnect-confirm' ) ) ?></p>- </div>- <div class="fs-modal-footer">- <button class="button button-primary<?php if ( is_object( $license ) ) : ?> warn<?php endif ?>" tabindex="2"><?php echo $fs->esc_html_inline( 'Yes', 'yes' ) . ' - ' . $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?></button>- <button class="button button-secondary button-close" tabindex="1"><?php echo esc_html( $fs->get_text_inline( 'Cancel', 'cancel' ) ) ?></button>- </div>- </div>-</div>-<form action="<?php echo esc_attr( $fs->_get_admin_page_url( 'account' ) ); ?>" method="POST">- <input type="hidden" name="fs_action" value="delete_account">- <?php wp_nonce_field( 'delete_account' ) ?>-- <a id="<?php echo $button_id ?>" href="#" class="fs-button-inline">- <i class="dashicons dashicons-no"></i>- <?php echo $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?>- </a>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2016, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.5.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = $VARS['freemius']; + + /** + * @var FS_Plugin_License $license + */ + $license = $VARS['license']; + /** + * @var FS_Plugin_Plan $license_paid_plan + */ + $license_paid_plan = $VARS['license_paid_plan']; + + $license_subscription = ( is_object( $license ) && is_object( $license_paid_plan ) ) ? + $fs->_get_subscription( $license->id ) : + null; + + $has_active_subscription = ( + is_object( $license_subscription ) && + $license_subscription->is_active() + ); + + $button_id = "fs_disconnect_button_{$fs->get_id()}"; + + $website_link = sprintf( '<a href="#" tabindex="-1">%s</a>', fs_strip_url_protocol( untrailingslashit( Freemius::get_unfiltered_site_url() ) ) ); +?> +<script type="text/javascript"> + // Wrap in a IFFE to prevent leaking global variables. + ( function( $ ) { + $( document ).ready( function() { + var $modal = $( '#fs_modal_delete_site' ); + + $( '#<?php echo $button_id ?>' ).on( 'click', function( e ) { + // Prevent the form being submitted. + e.preventDefault(); + + $( document.body ).append( $modal ); + $modal.show(); + } ); + + $modal.on( 'click', '.button-close', function ( evt ) { + $modal.hide(); + } ); + + $modal.on( 'click', '.button-primary', function ( evt ) { + $( '#<?php echo $button_id ?>' ).closest( 'form' )[0].submit(); + } ); + } ); + } )( jQuery ); +</script> +<div id="fs_modal_delete_site" class="fs-modal active" style="display: none"> + <div class="fs-modal-dialog"> + <div class="fs-modal-header"> + <h4><?php echo $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?></h4> + </div> + <div class="fs-modal-body"> + <?php if ( ! is_object( $license ) ) : ?> + <p><?php echo + // translators: %1$s is replaced with the website's homepage address, %2$s is replaced with the plugin name. + sprintf( esc_html( $fs->get_text_inline( 'By disconnecting the website, previously shared diagnostic data about %1$s will be deleted and no longer visible to %2$s.', 'disconnect-intro-paid' ) ), $website_link, '<b>' . $fs->get_plugin_title() . '</b>' ) ?></p> + <?php else : ?> + <p><?php echo + // translators: %s is replaced with the website's homepage address. + sprintf( esc_html( $fs->get_text_inline( 'Disconnecting the website will permanently remove %s from your User Dashboard\'s account.', 'disconnect-intro-paid' ) ), $website_link ) ?></p> + <?php endif ?> + + <?php if ( $has_active_subscription ) : ?> + <p><?php echo + // translators: %1$s is replaced by the paid plan name, %2$s is replaced with an anchor link with the text "User Dashboard". + sprintf( esc_html( $fs->get_text_inline( 'If you wish to cancel your %1$s plan\'s subscription instead, please navigate to the %2$s and cancel it there.', 'disconnect-subscription-disclaimer' ) ), $license_paid_plan->title, sprintf( '<a href="https://users.freemius.com" target="_blank" rel="noreferrer noopener nofollow">%s</a>', $fs->get_text_inline( 'User Dashboard', 'user-dashboard' ) ) + ) ?></p> + <?php endif ?> + + <p><?php echo esc_html( $fs->get_text_inline( 'Are you sure you would like to proceed with the disconnection?', 'disconnect-confirm' ) ) ?></p> + </div> + <div class="fs-modal-footer"> + <button class="button button-primary<?php if ( is_object( $license ) ) : ?> warn<?php endif ?>" tabindex="2"><?php echo $fs->esc_html_inline( 'Yes', 'yes' ) . ' - ' . $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?></button> + <button class="button button-secondary button-close" tabindex="1"><?php echo esc_html( $fs->get_text_inline( 'Cancel', 'cancel' ) ) ?></button> + </div> + </div> +</div> +<form action="<?php echo esc_attr( $fs->_get_admin_page_url( 'account' ) ); ?>" method="POST"> + <input type="hidden" name="fs_action" value="delete_account"> + <?php wp_nonce_field( 'delete_account' ) ?> + + <a id="<?php echo $button_id ?>" href="#" class="fs-button-inline"> + <i class="dashicons dashicons-no"></i> + <?php echo $fs->esc_html_inline( 'Disconnect', 'disconnect' ) ?> + </a> </form>\ No newline at end of file
Vulnerability Existed: no No CWE Vulnerabilities Identified Explanation: This diff shows only whitespace and line ending changes (converting from Unix LF to DOS CRLF or similar line ending format). There are no functional code changes, no removal or modification of security controls, and no introduction of new vulnerable patterns. The file content remains identical in terms of: - Security functions (nonce validation via `wp_nonce_field()`) - Output escaping (proper use of `esc_html()`, `esc_attr()`, `esc_html_inline()`) - XSS prevention measures - CSRF protection (nonce field present) - Data validation and sanitization patterns The diff represents a formatting-only change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/account/partials/index.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/account/partials/index.php 2026-01-19 00:17:37.671046273 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Vulnerability - File: inc/freemius/templates/account/partials/index.php [Lines 1-3] Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace changes (tab/space normalization on lines 1-2). No security-related code modifications were made. The file structure and content remain functionally identical. The "Silence is golden" pattern is a standard PHP security practice that prevents direct file access by ensuring the file outputs nothing when accessed directly, which does not introduce or fix any vulnerabilities. This is a formatting/style change only, not a security fix.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/account/payments.php 2026-01-19 00:16:00.461015685 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/account/payments.php 2026-01-19 00:17:37.671046273 +0000@@ -1,58 +1,58 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2016, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );-- /**- * @var FS_Payment[] $payments- */- $payments = $VARS['payments'];-- $slug = $fs->get_slug();--?>-<div class="postbox">- <div id="fs_payments">- <h3><span class="dashicons dashicons-paperclip"></span> <?php fs_esc_html_echo_inline( 'Payments', 'payments', $slug ) ?></h3>-- <div class="inside">- <table class="widefat">- <thead>- <tr>- <th><?php fs_esc_html_echo_inline( 'ID', 'id', $slug ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Date', 'date', $slug ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Amount', 'amount', $slug ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Invoice', 'invoice', $slug ) ?></th>- </tr>- </thead>- <tbody>- <?php $odd = true ?>- <?php foreach ( $payments as $payment ) : ?>- <tr<?php echo $odd ? ' class="alternate"' : '' ?>>- <td><?php echo $payment->id ?></td>- <td><?php echo date( 'M j, Y', strtotime( $payment->created ) ) ?></td>- <td><?php echo $payment->formatted_gross() ?></td>- <td><?php if (! $payment->is_migrated() ) : ?><a href="<?php echo $fs->_get_invoice_api_url( $payment->id ) ?>"- class="button button-small"- target="_blank" rel="noopener"><?php fs_esc_html_echo_inline( 'Invoice', 'invoice', $slug ) ?></a><?php endif ?></td>- </tr>- <?php $odd = ! $odd; endforeach ?>- </tbody>- </table>- </div>- </div>-</div>-<?php+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2016, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + + /** + * @var FS_Payment[] $payments + */ + $payments = $VARS['payments']; + + $slug = $fs->get_slug(); + +?> +<div class="postbox"> + <div id="fs_payments"> + <h3><span class="dashicons dashicons-paperclip"></span> <?php fs_esc_html_echo_inline( 'Payments', 'payments', $slug ) ?></h3> + + <div class="inside"> + <table class="widefat"> + <thead> + <tr> + <th><?php fs_esc_html_echo_inline( 'ID', 'id', $slug ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Date', 'date', $slug ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Amount', 'amount', $slug ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Invoice', 'invoice', $slug ) ?></th> + </tr> + </thead> + <tbody> + <?php $odd = true ?> + <?php foreach ( $payments as $payment ) : ?> + <tr<?php echo $odd ? ' class="alternate"' : '' ?>> + <td><?php echo $payment->id ?></td> + <td><?php echo date( 'M j, Y', strtotime( $payment->created ) ) ?></td> + <td><?php echo $payment->formatted_gross() ?></td> + <td><?php if (! $payment->is_migrated() ) : ?><a href="<?php echo $fs->_get_invoice_api_url( $payment->id ) ?>" + class="button button-small" + target="_blank" rel="noopener"><?php fs_esc_html_echo_inline( 'Invoice', 'invoice', $slug ) ?></a><?php endif ?></td> + </tr> + <?php $odd = ! $odd; endforeach ?> + </tbody> + </table> + </div> + </div> +</div> +<?php
Based on my analysis of the provided code diff, here is the security assessment:
---
**Vulnerability Existed: no**
**No Security Vulnerabilities Identified** - inc/freemius/templates/account/payments.php (All lines)
**Old Code:**
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2016, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ... [full file content as shown in diff]
```
**Fixed Code:**
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2016, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// ... [full file content as shown in diff]
```
**Explanation:**
The diff shows only line ending changes (CRLF to LF conversion) with no substantive code modifications. The file content remains functionally identical between versions 1.2.11 and 1.2.12. No security vulnerabilities were introduced or fixed in this update. The code continues to use appropriate security functions:
- `fs_esc_html_echo_inline()` for output escaping
- `$fs->_get_invoice_api_url()` for URL generation
- WordPress security best practices (ABSPATH check, proper context usage)
The change appears to be purely a formatting/line-ending normalization commit with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/add-trial-to-pricing.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/add-trial-to-pricing.php 2026-01-19 00:17:37.671046273 +0000@@ -1,31 +1,31 @@-<?php- /**- * Add "&trial=true" to pricing menu item href when running in trial- * promotion context.- *- * @package Freemius- * @copyright Copyright (c) 2016, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.1.5- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );-?>-<script type="text/javascript">- (function ($) {- $(document).ready(function () {- var $pricingMenu = $('.fs-submenu-item.<?php echo $fs->get_unique_affix() ?>.pricing'),- $pricingMenuLink = $pricingMenu.parents('a');-- // Add trial querystring param.- $pricingMenuLink.attr('href', $pricingMenuLink.attr('href') + '&trial=true');- });- })(jQuery);+<?php + /** + * Add "&trial=true" to pricing menu item href when running in trial + * promotion context. + * + * @package Freemius + * @copyright Copyright (c) 2016, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.1.5 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); +?> +<script type="text/javascript"> + (function ($) { + $(document).ready(function () { + var $pricingMenu = $('.fs-submenu-item.<?php echo $fs->get_unique_affix() ?>.pricing'), + $pricingMenuLink = $pricingMenu.parents('a'); + + // Add trial querystring param. + $pricingMenuLink.attr('href', $pricingMenuLink.attr('href') + '&trial=true'); + }); + })(jQuery); </script>\ No newline at end of file
Vulnerability Existed: no Explanation: This diff contains only whitespace and line ending changes (Unix/Linux line endings replacing Windows line endings). There are no functional code modifications, security fixes, or vulnerability-related changes in this file. The code itself does contain a potential security concern (direct output of `$fs->get_unique_affix()` without escaping in a JavaScript context at line 25), but this pre-existed in the original version and is not addressed by this diff. The diff does not introduce or fix any vulnerabilities—it only reformats the file with consistent line endings.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/admin-notice.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/admin-notice.php 2026-01-19 00:17:37.671046273 +0000@@ -1,112 +1,112 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- */-- $dismiss_text = fs_text_x_inline( 'Dismiss', 'as close a window', 'dismiss' );-- $slug = '';- $type = '';-- if ( ! empty( $VARS['manager_id'] ) ) {- /**- * @var array $VARS- */- $slug = $VARS['manager_id'];-- $type = WP_FS__MODULE_TYPE_PLUGIN;-- if ( false !== strpos( $slug, ':' ) ) {- $parts = explode( ':', $slug );-- $slug = $parts[0];-- $parts_count = count( $parts );-- if ( 1 < $parts_count && WP_FS__MODULE_TYPE_THEME == $parts[1] ) {- $type = $parts[1];- }- }- }-- $attributes = array();- if ( ! empty( $VARS['id'] ) ) {- $attributes['data-id'] = $VARS['id'];- }- if ( ! empty( $VARS['manager_id'] ) ) {- $attributes['data-manager-id'] = $VARS['manager_id'];- }- if ( ! empty( $slug ) ) {- $attributes['data-slug'] = $slug;- }- if ( ! empty( $type ) ) {- $attributes['data-type'] = $type;- }-- $classes = array( 'fs-notice' );- switch ( $VARS['type'] ) {- case 'error':- $classes[] = 'error';- $classes[] = 'form-invalid';- break;- case 'promotion':- $classes[] = 'updated';- $classes[] = 'promotion';- break;- case 'warn':- $classes[] = 'notice';- $classes[] = 'notice-warning';- break;- case 'update':- case 'success':- default:- $classes[] = 'updated';- $classes[] = 'success';- break;- }- if ( ! empty( $VARS['sticky'] ) ) {- $classes[] = 'fs-sticky';- }- if ( ! empty( $VARS['plugin'] ) ) {- $classes[] = 'fs-has-title';- }- if ( ! empty( $slug ) ) {- $classes[] = "fs-slug-{$slug}";- }- if ( ! empty( $type ) ) {- $classes[] = "fs-type-{$type}";- }-?>-<div class="<?php echo fs_html_get_classname( $classes ); ?>" <?php echo fs_html_get_attributes( $attributes ); ?>>- <?php if ( ! empty( $VARS['plugin'] ) ) : ?>- <label class="fs-plugin-title">- <?php echo esc_html( $VARS['plugin'] ); ?>- </label>- <?php endif ?>-- <?php if ( ! empty( $VARS['sticky'] ) && ( ! isset( $VARS['dismissible'] ) || false !== $VARS['dismissible'] ) ) : ?>- <div class="fs-close">- <i class="dashicons dashicons-no" title="<?php echo esc_attr( $dismiss_text ) ?>"></i>- <span><?php echo esc_html( $dismiss_text ); ?></span>- </div>- <?php endif ?>-- <div class="fs-notice-body">- <?php if ( ! empty( $VARS['title'] ) ) : ?>- <strong><?php echo fs_html_get_sanitized_html( $VARS['title'] ); ?></strong>- <?php endif ?>-- <?php echo fs_html_get_sanitized_html( $VARS['message'] ); ?>- </div>-</div>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + */ + + $dismiss_text = fs_text_x_inline( 'Dismiss', 'as close a window', 'dismiss' ); + + $slug = ''; + $type = ''; + + if ( ! empty( $VARS['manager_id'] ) ) { + /** + * @var array $VARS + */ + $slug = $VARS['manager_id']; + + $type = WP_FS__MODULE_TYPE_PLUGIN; + + if ( false !== strpos( $slug, ':' ) ) { + $parts = explode( ':', $slug ); + + $slug = $parts[0]; + + $parts_count = count( $parts ); + + if ( 1 < $parts_count && WP_FS__MODULE_TYPE_THEME == $parts[1] ) { + $type = $parts[1]; + } + } + } + + $attributes = array(); + if ( ! empty( $VARS['id'] ) ) { + $attributes['data-id'] = $VARS['id']; + } + if ( ! empty( $VARS['manager_id'] ) ) { + $attributes['data-manager-id'] = $VARS['manager_id']; + } + if ( ! empty( $slug ) ) { + $attributes['data-slug'] = $slug; + } + if ( ! empty( $type ) ) { + $attributes['data-type'] = $type; + } + + $classes = array( 'fs-notice' ); + switch ( $VARS['type'] ) { + case 'error': + $classes[] = 'error'; + $classes[] = 'form-invalid'; + break; + case 'promotion': + $classes[] = 'updated'; + $classes[] = 'promotion'; + break; + case 'warn': + $classes[] = 'notice'; + $classes[] = 'notice-warning'; + break; + case 'update': + case 'success': + default: + $classes[] = 'updated'; + $classes[] = 'success'; + break; + } + if ( ! empty( $VARS['sticky'] ) ) { + $classes[] = 'fs-sticky'; + } + if ( ! empty( $VARS['plugin'] ) ) { + $classes[] = 'fs-has-title'; + } + if ( ! empty( $slug ) ) { + $classes[] = "fs-slug-{$slug}"; + } + if ( ! empty( $type ) ) { + $classes[] = "fs-type-{$type}"; + } +?> +<div class="<?php echo fs_html_get_classname( $classes ); ?>" <?php echo fs_html_get_attributes( $attributes ); ?>> + <?php if ( ! empty( $VARS['plugin'] ) ) : ?> + <label class="fs-plugin-title"> + <?php echo esc_html( $VARS['plugin'] ); ?> + </label> + <?php endif ?> + + <?php if ( ! empty( $VARS['sticky'] ) && ( ! isset( $VARS['dismissible'] ) || false !== $VARS['dismissible'] ) ) : ?> + <div class="fs-close"> + <i class="dashicons dashicons-no" title="<?php echo esc_attr( $dismiss_text ) ?>"></i> + <span><?php echo esc_html( $dismiss_text ); ?></span> + </div> + <?php endif ?> + + <div class="fs-notice-body"> + <?php if ( ! empty( $VARS['title'] ) ) : ?> + <strong><?php echo fs_html_get_sanitized_html( $VARS['title'] ); ?></strong> + <?php endif ?> + + <?php echo fs_html_get_sanitized_html( $VARS['message'] ); ?> + </div> +</div>
Vulnerability Existed: no No Security Vulnerabilities Detected - inc/freemius/templates/admin-notice.php Explanation: The diff shows only whitespace/line ending changes (converting line endings from Unix to Windows format or vice versa). The actual code logic remains identical between versions 1.2.11 and 1.2.12. The code does not introduce or fix any security vulnerabilities: - The template properly uses `esc_html()` for text output (lines 97, 103, 104) - The template uses `esc_attr()` for HTML attributes (line 101) - The template uses `fs_html_get_sanitized_html()` for rich HTML content (lines 108, 111) - Input validation through `! empty()` checks is consistently applied throughout - No new code paths, logic, or data handling has been introduced in this diff This is a formatting-only change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/ajax-loader.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/ajax-loader.php 2026-01-19 00:17:37.671046273 +0000@@ -1,6 +1,6 @@-<?php- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-?>-<div class="fs-ajax-loader" style="display: none"><?php for ( $i = 1; $i <= 8; $i ++ ) : ?><div class="fs-ajax-loader-bar fs-ajax-loader-bar-<?php echo $i ?>"></div><?php endfor ?></div>+<?php + if ( ! defined( 'ABSPATH' ) ) { + exit; + } +?> +<div class="fs-ajax-loader" style="display: none"><?php for ( $i = 1; $i <= 8; $i ++ ) : ?><div class="fs-ajax-loader-bar fs-ajax-loader-bar-<?php echo $i ?>"></div><?php endfor ?></div>
Vulnerability Existed: no
No Security Vulnerabilities Detected - [N/A] - inc/freemius/templates/ajax-loader.php [1-6]
Old Code:
```php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<div class="fs-ajax-loader" style="display: none"><?php for ( $i = 1; $i <= 8; $i ++ ) : ?><div class="fs-ajax-loader-bar fs-ajax-loader-bar-<?php echo $i ?>"></div><?php endfor ?></div>
```
Fixed Code:
```php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<div class="fs-ajax-loader" style="display: none"><?php for ( $i = 1; $i <= 8; $i ++ ) : ?><div class="fs-ajax-loader-bar fs-ajax-loader-bar-<?php echo $i ?>"></div><?php endfor ?></div>
```
Explanation:
The diff shows only whitespace/line ending changes (Unix line endings). The actual code logic remains identical between versions. No security fixes or vulnerabilities are present. The code already contains proper WordPress security practices:
- ABSPATH check prevents direct file access
- Integer variable `$i` is safely echoed without user input
- No database queries, file operations, or external data handling
- No output that requires escaping
This is a formatting-only change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/api-connectivity-message-js.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/api-connectivity-message-js.php 2026-01-19 00:17:37.675046521 +0000@@ -1,32 +1,32 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.5.4- */- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-?>-<script type="text/javascript">- ( function( $ ) {- $( document ).ready(function() {- var $parent = $( '.fs-notice, #fs_connect, .fs-modal' );-- $parent.on( 'click', '.fs-api-request-error-show-details-link', function () {- var $error_details_container = $parent.find( '.fs-api-request-error-details' );-- $error_details_container.toggle();-- $( this ).find( 'span' ).prop( 'class',- $error_details_container.is( ':visible' ) ?- 'dashicons dashicons-arrow-up-alt2' :- 'dashicons dashicons-arrow-down-alt2'- );-- return false;- } );- } );- } )( jQuery );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.5.4 + */ + if ( ! defined( 'ABSPATH' ) ) { + exit; + } +?> +<script type="text/javascript"> + ( function( $ ) { + $( document ).ready(function() { + var $parent = $( '.fs-notice, #fs_connect, .fs-modal' ); + + $parent.on( 'click', '.fs-api-request-error-show-details-link', function () { + var $error_details_container = $parent.find( '.fs-api-request-error-details' ); + + $error_details_container.toggle(); + + $( this ).find( 'span' ).prop( 'class', + $error_details_container.is( ':visible' ) ? + 'dashicons dashicons-arrow-up-alt2' : + 'dashicons dashicons-arrow-down-alt2' + ); + + return false; + } ); + } ); + } )( jQuery ); </script>\ No newline at end of file
Vulnerability Existed: no Explanation: This diff shows only line ending changes (CRLF to LF conversion) with no actual code modifications. The file content remains functionally identical between versions 1.2.11 and 1.2.12. There are no security-relevant code changes, no new vulnerabilities introduced, and no existing vulnerabilities fixed. The jQuery event handler code, DOM manipulation, and PHP security checks remain unchanged.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/auto-installation.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/auto-installation.php 2026-01-19 00:17:37.675046521 +0000@@ -1,249 +1,249 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.1.5- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $slug = $VARS['slug'];- $plugin_id = $VARS['target_module_id'];-- $fs = freemius( $VARS['id'] );-- $action = $fs->is_tracking_allowed() ?- 'stop_tracking' :- 'allow_tracking';-- $title = $fs->get_plugin_title();-- if ( $plugin_id != $fs->get_id() ) {- $addon = $fs->get_addon( $plugin_id );-- if ( is_object( $addon ) ) {- $title = $addon->title . ' ' . fs_text_inline( 'Add-On', 'addon', $slug );- }- }-- $plugin_title = sprintf(- '<strong>%s</strong>',- esc_html( $title )- );-- $sec_countdown = 30;- $countdown_html = sprintf(- esc_js(- /* translators: %s: Number of seconds */- fs_text_inline( '%s sec', 'x-sec', $slug )- ),- sprintf( '<span class="fs-countdown">%s</span>', $sec_countdown )- );-- fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );- fs_enqueue_local_style( 'fs_common', '/admin/common.css' );-- $params = array();- $loader_html = fs_get_template( 'ajax-loader.php', $params );-- // Pass unique auto installation URL if WP_Filesystem is needed.- $install_url = $fs->_get_sync_license_url(- $plugin_id,- true,- array( 'auto_install' => 'true' )- );--- ob_start();-- $method = ''; // Leave blank so WP_Filesystem can populate it as necessary.-- $credentials = request_filesystem_credentials(- esc_url_raw( $install_url ),- $method,- false,- WP_PLUGIN_DIR,- array()- );-- $credentials_form = ob_get_clean();-- $require_credentials = ! empty( $credentials_form );-?>-<div class="fs-modal fs-modal-auto-install">- <div class="fs-modal-dialog">- <div class="fs-modal-header">- <h4><?php echo esc_js( fs_text_inline( 'Automatic Installation', 'auto-installation', $slug ) ) ?></h4>- </div>- <div class="fs-modal-body">- <div class="fs-notice-error" style="display: none"><p></p></div>- <?php if ( $require_credentials ) : ?>- <div id="request-filesystem-credentials-dialog">- <?php echo $credentials_form ?>- </div>- <?php else : ?>- <p class="fs-installation-notice"><?php echo sprintf(- fs_esc_html_inline( 'An automated download and installation of %s (paid version) from %s will start in %s. If you would like to do it manually - click the cancellation button now.', 'installing-in-n', $slug ),- $plugin_title,- sprintf(- '<a href="%s" target="_blank" rel="noopener">%s</a>',- 'https://freemius.com',- 'freemius.com'- ),- $countdown_html- ) ?></p>- <?php endif ?>- <p class="fs-installing"- style="display: none"><?php echo sprintf( fs_esc_html_inline( 'The installation process has started and may take a few minutes to complete. Please wait until it is done - do not refresh this page.', 'installing-module-x', $slug ), $plugin_title ) ?></p>- </div>- <div class="fs-modal-footer">- <?php echo $loader_html ?>- <button- class="button button-secondary button-cancel"><?php fs_esc_html_echo_inline( 'Cancel Installation', 'cancel-installation', $slug ) ?><?php if ( ! $require_credentials ) : ?> (<?php echo $countdown_html ?>)<?php endif ?></button>- <button- class="button button-primary"><?php fs_esc_html_echo_inline( 'Install Now', 'install-now', $slug ) ?></button>- </div>- </div>-</div>'--<script type="text/javascript">- (function ($) {- $(document).ready(function () {- var $modal = $('.fs-modal-auto-install'),- $body = $('body'),- $countdown = $modal.find('.fs-countdown'),- requireCredentials = <?php echo json_encode( $require_credentials ) ?>,- $credentialsForm = $('#request-filesystem-credentials-dialog'),- $errorNotice = $modal.find('.fs-notice-error'),- installing = false;-- $modal.appendTo($body);-- var startAutoInstall = function () {- if (installing)- return;-- installing = true;-- // Start auto-install.- $modal.addClass('fs-warn');- if (requireCredentials) {- $credentialsForm.hide();- } else {- $modal.find('.fs-installation-notice').hide();- }-- $errorNotice.hide();- $modal.find('.fs-installing').show();- $modal.find('button').hide();- $modal.find('.fs-ajax-loader').show();-- var data = {- action : '<?php echo $fs->get_ajax_action( 'install_premium_version' ) ?>',- security : '<?php echo $fs->get_ajax_security( 'install_premium_version' ) ?>',- slug : '<?php echo $slug ?>',- module_id : '<?php echo $fs->get_id() ?>',- target_module_id: '<?php echo $plugin_id ?>'- };-- if (requireCredentials) {- // Add filesystem credentials.- data.hostname = $('#hostname').val();- data.username = $('#username').val();- data.password = $('#password').val();- data.connection_type = $('input[name="connection_type"]:checked').val();- data.public_key = $('#public_key').val();- data.private_key = $('#private_key').val();- }-- $.ajax({- url : <?php echo Freemius::ajax_url() ?>,- method : 'POST',- data : data,- success: function (resultObj) {- var reloadAccount = false;-- if (resultObj.success) {- // Reload account page to show new data.- reloadAccount = true;- } else {- switch (resultObj.error.code) {- case 'invalid_module_id':- case 'premium_installed':- reloadAccount = true;- break;- case 'invalid_license':- case 'premium_version_missing':- case 'unable_to_connect_to_filesystem':- default:- $modal.removeClass('fs-warn');- $modal.find('.fs-installing').hide();- $modal.find('.fs-ajax-loader').hide();- $modal.find('.button-cancel').html(<?php fs_json_encode_echo_inline( 'Cancel Installation', 'cancel-installation', $slug ) ?>);- $modal.find('button').show();-- $errorNotice.find('p').text(resultObj.error.message);- $errorNotice.addClass('notice notice-alt notice-error').show();- if (requireCredentials) {- $credentialsForm.show();- }- break;- }- }-- if (reloadAccount) {- window.location = '<?php echo $fs->get_account_url() ?>';- }-- installing = false;- }- });- };-- var clearCountdown = function () {- clearInterval(countdownInterval);- countdownInterval = null;- };-- var cancelAutoInstall = function () {- $modal.fadeOut(function () {- $modal.remove();- $body.removeClass('has-fs-modal');- });- };-- var countdown = <?php echo $sec_countdown ?>,- countdownInterval = requireCredentials ? null : setInterval(function () {- $countdown.html(--countdown);- if (0 == countdown) {- clearCountdown();- startAutoInstall();- }- }, 1000);-- $modal.addClass('active');- $body.addClass('has-fs-modal');-- $modal.find('.button-primary').click(function () {- clearCountdown();- startAutoInstall();- });-- $modal.find('.button-cancel').click(function () {- clearCountdown();- cancelAutoInstall();- });-- if (requireCredentials) {-- }- });- })(jQuery);-</script>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.1.5 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $slug = $VARS['slug']; + $plugin_id = $VARS['target_module_id']; + + $fs = freemius( $VARS['id'] ); + + $action = $fs->is_tracking_allowed() ? + 'stop_tracking' : + 'allow_tracking'; + + $title = $fs->get_plugin_title(); + + if ( $plugin_id != $fs->get_id() ) { + $addon = $fs->get_addon( $plugin_id ); + + if ( is_object( $addon ) ) { + $title = $addon->title . ' ' . fs_text_inline( 'Add-On', 'addon', $slug ); + } + } + + $plugin_title = sprintf( + '<strong>%s</strong>', + esc_html( $title ) + ); + + $sec_countdown = 30; + $countdown_html = sprintf( + esc_js( + /* translators: %s: Number of seconds */ + fs_text_inline( '%s sec', 'x-sec', $slug ) + ), + sprintf( '<span class="fs-countdown">%s</span>', $sec_countdown ) + ); + + fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' ); + fs_enqueue_local_style( 'fs_common', '/admin/common.css' ); + + $params = array(); + $loader_html = fs_get_template( 'ajax-loader.php', $params ); + + // Pass unique auto installation URL if WP_Filesystem is needed. + $install_url = $fs->_get_sync_license_url( + $plugin_id, + true, + array( 'auto_install' => 'true' ) + ); + + + ob_start(); + + $method = ''; // Leave blank so WP_Filesystem can populate it as necessary. + + $credentials = request_filesystem_credentials( + esc_url_raw( $install_url ), + $method, + false, + WP_PLUGIN_DIR, + array() + ); + + $credentials_form = ob_get_clean(); + + $require_credentials = ! empty( $credentials_form ); +?> +<div class="fs-modal fs-modal-auto-install"> + <div class="fs-modal-dialog"> + <div class="fs-modal-header"> + <h4><?php echo esc_js( fs_text_inline( 'Automatic Installation', 'auto-installation', $slug ) ) ?></h4> + </div> + <div class="fs-modal-body"> + <div class="fs-notice-error" style="display: none"><p></p></div> + <?php if ( $require_credentials ) : ?> + <div id="request-filesystem-credentials-dialog"> + <?php echo $credentials_form ?> + </div> + <?php else : ?> + <p class="fs-installation-notice"><?php echo sprintf( + fs_esc_html_inline( 'An automated download and installation of %s (paid version) from %s will start in %s. If you would like to do it manually - click the cancellation button now.', 'installing-in-n', $slug ), + $plugin_title, + sprintf( + '<a href="%s" target="_blank" rel="noopener">%s</a>', + 'https://freemius.com', + 'freemius.com' + ), + $countdown_html + ) ?></p> + <?php endif ?> + <p class="fs-installing" + style="display: none"><?php echo sprintf( fs_esc_html_inline( 'The installation process has started and may take a few minutes to complete. Please wait until it is done - do not refresh this page.', 'installing-module-x', $slug ), $plugin_title ) ?></p> + </div> + <div class="fs-modal-footer"> + <?php echo $loader_html ?> + <button + class="button button-secondary button-cancel"><?php fs_esc_html_echo_inline( 'Cancel Installation', 'cancel-installation', $slug ) ?><?php if ( ! $require_credentials ) : ?> (<?php echo $countdown_html ?>)<?php endif ?></button> + <button + class="button button-primary"><?php fs_esc_html_echo_inline( 'Install Now', 'install-now', $slug ) ?></button> + </div> + </div> +</div>' + +<script type="text/javascript"> + (function ($) { + $(document).ready(function () { + var $modal = $('.fs-modal-auto-install'), + $body = $('body'), + $countdown = $modal.find('.fs-countdown'), + requireCredentials = <?php echo json_encode( $require_credentials ) ?>, + $credentialsForm = $('#request-filesystem-credentials-dialog'), + $errorNotice = $modal.find('.fs-notice-error'), + installing = false; + + $modal.appendTo($body); + + var startAutoInstall = function () { + if (installing) + return; + + installing = true; + + // Start auto-install. + $modal.addClass('fs-warn'); + if (requireCredentials) { + $credentialsForm.hide(); + } else { + $modal.find('.fs-installation-notice').hide(); + } + + $errorNotice.hide(); + $modal.find('.fs-installing').show(); + $modal.find('button').hide(); + $modal.find('.fs-ajax-loader').show(); + + var data = { + action : '<?php echo $fs->get_ajax_action( 'install_premium_version' ) ?>', + security : '<?php echo $fs->get_ajax_security( 'install_premium_version' ) ?>', + slug : '<?php echo $slug ?>', + module_id : '<?php echo $fs->get_id() ?>', + target_module_id: '<?php echo $plugin_id ?>' + }; + + if (requireCredentials) { + // Add filesystem credentials. + data.hostname = $('#hostname').val(); + data.username = $('#username').val(); + data.password = $('#password').val(); + data.connection_type = $('input[name="connection_type"]:checked').val(); + data.public_key = $('#public_key').val(); + data.private_key = $('#private_key').val(); + } + + $.ajax({ + url : <?php echo Freemius::ajax_url() ?>, + method : 'POST', + data : data, + success: function (resultObj) { + var reloadAccount = false; + + if (resultObj.success) { + // Reload account page to show new data. + reloadAccount = true; + } else { + switch (resultObj.error.code) { + case 'invalid_module_id': + case 'premium_installed': + reloadAccount = true; + break; + case 'invalid_license': + case 'premium_version_missing': + case 'unable_to_connect_to_filesystem': + default: + $modal.removeClass('fs-warn'); + $modal.find('.fs-installing').hide(); + $modal.find('.fs-ajax-loader').hide(); + $modal.find('.button-cancel').html(<?php fs_json_encode_echo_inline( 'Cancel Installation', 'cancel-installation', $slug ) ?>); + $modal.find('button').show(); + + $errorNotice.find('p').text(resultObj.error.message); + $errorNotice.addClass('notice notice-alt notice-error').show(); + if (requireCredentials) { + $credentialsForm.show(); + } + break; + } + } + + if (reloadAccount) { + window.location = '<?php echo $fs->get_account_url() ?>'; + } + + installing = false; + } + }); + }; + + var clearCountdown = function () { + clearInterval(countdownInterval); + countdownInterval = null; + }; + + var cancelAutoInstall = function () { + $modal.fadeOut(function () { + $modal.remove(); + $body.removeClass('has-fs-modal'); + }); + }; + + var countdown = <?php echo $sec_countdown ?>, + countdownInterval = requireCredentials ? null : setInterval(function () { + $countdown.html(--countdown); + if (0 == countdown) { + clearCountdown(); + startAutoInstall(); + } + }, 1000); + + $modal.addClass('active'); + $body.addClass('has-fs-modal'); + + $modal.find('.button-primary').click(function () { + clearCountdown(); + startAutoInstall(); + }); + + $modal.find('.button-cancel').click(function () { + clearCountdown(); + cancelAutoInstall(); + }); + + if (requireCredentials) { + + } + }); + })(jQuery); +</script>
Vulnerability Existed: no **Analysis:** This diff shows only line ending changes (LF to CRLF or vice versa) between version 1.2.11 and 1.2.12. The actual code content is identical - no functional changes, logic modifications, or security fixes are present. The file maintains the same security characteristics: - Uses `esc_html()`, `esc_js()`, and `esc_url_raw()` for output escaping - Uses `json_encode()` for JavaScript context - Implements WordPress nonce verification through the Freemius framework - No new code has been introduced that could introduce vulnerabilities **Conclusion:** No security vulnerabilities were added or fixed in this update. This is a whitespace-only change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/checkout.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/checkout.php 2026-01-19 00:17:37.675046521 +0000@@ -1,340 +1,340 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- /**- * Note for WordPress.org Theme/Plugin reviewer:- * Freemius is an SDK for plugin and theme developers. Since the core- * of the SDK is relevant both for plugins and themes, for obvious reasons,- * we only develop and maintain one code base.- *- * This code (and page) will not run for wp.org themes (only plugins).- *- * In addition, this page loads an i-frame. We intentionally named it 'frame'- * so it will pass the "Theme Check" that is looking for the string "i" . "frame".- *- * UPDATE:- * After ongoing conversations with the WordPress.org TRT we received- * an official approval for including i-frames in the theme's WP Admin setting's- * page tab (the SDK will never add any i-frames on the sitefront). i-frames- * were never against the guidelines, but we wanted to get the team's blessings- * before we move forward. For the record, I got the final approval from- * Ulrich Pogson (@grapplerulrich), a team lead at the TRT during WordCamp- * Europe 2017 (June 16th, 2017).- *- * If you have any questions or need clarifications, please don't hesitate- * pinging me on slack, my username is @svovaf.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- wp_enqueue_script( 'jquery' );- wp_enqueue_script( 'json2' );- fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' );- fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );- fs_enqueue_local_style( 'fs_common', '/admin/common.css' );-- fs_enqueue_local_style( 'fs_checkout', '/admin/checkout.css' );-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );- $slug = $fs->get_slug();-- $timestamp = time();-- $context_params = array(- 'plugin_id' => $fs->get_id(),- 'public_key' => $fs->get_public_key(),- 'plugin_version' => $fs->get_plugin_version(),- 'mode' => 'dashboard',- 'trial' => fs_request_get_bool( 'trial' ),- 'is_ms' => ( fs_is_network_admin() && $fs->is_network_active() ),- );-- $plan_id = fs_request_get( 'plan_id' );- if ( FS_Plugin_Plan::is_valid_id( $plan_id ) ) {- $context_params['plan_id'] = $plan_id;- }-- $licenses = fs_request_get( 'licenses' );- if ( $licenses === strval( intval( $licenses ) ) && $licenses > 0 ) {- $context_params['licenses'] = $licenses;- }-- $plugin_id = fs_request_get( 'plugin_id' );- if ( ! FS_Plugin::is_valid_id( $plugin_id ) ) {- $plugin_id = $fs->get_id();- }-- if ( $plugin_id == $fs->get_id() ) {- $is_premium = $fs->is_premium();-- $bundle_id = $fs->get_bundle_id();- if ( ! is_null( $bundle_id ) ) {- $context_params['bundle_id'] = $bundle_id;- }- } else {- // Identify the module code version of the checkout context module.- if ( $fs->is_addon_activated( $plugin_id ) ) {- $fs_addon = Freemius::get_instance_by_id( $plugin_id );- $is_premium = $fs_addon->is_premium();- } else {- // If add-on isn't activated assume the premium version isn't installed.- $is_premium = false;- }- }-- // Get site context secure params.- if ( $fs->is_registered() ) {- $site = $fs->get_site();-- if ( $plugin_id != $fs->get_id() ) {- if ( $fs->is_addon_activated( $plugin_id ) ) {- $fs_addon = Freemius::get_instance_by_id( $plugin_id );- $addon_site = $fs_addon->get_site();- if ( is_object( $addon_site ) ) {- $site = $addon_site;- }- }- }-- $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(- $site,- $timestamp,- 'checkout'- ) );- } else {- $current_user = Freemius::_get_current_wp_user();-- // Add site and user info to the request, this information- // is NOT being stored unless the user complete the purchase- // and agrees to the TOS.- $context_params = array_merge( $context_params, array(- 'user_firstname' => $current_user->user_firstname,- 'user_lastname' => $current_user->user_lastname,- 'user_email' => $current_user->user_email,- 'home_url' => home_url(),- ) );-- $fs_user = Freemius::_get_user_by_email( $current_user->user_email );-- if ( is_object( $fs_user ) && $fs_user->is_verified() ) {- $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(- $fs_user,- $timestamp,- 'checkout'- ) );- }- }-- if ( $fs->is_payments_sandbox() ) {- // Append plugin secure token for sandbox mode authentication.- $context_params['sandbox'] = FS_Security::instance()->get_secure_token(- $fs->get_plugin(),- $timestamp,- 'checkout'- );-- /**- * @since 1.1.7.3 Add security timestamp for sandbox even for anonymous user.- */- if ( empty( $context_params['s_ctx_ts'] ) ) {- $context_params['s_ctx_ts'] = $timestamp;- }- }-- $return_url = $fs->_get_sync_license_url( $plugin_id );-- $can_user_install = (- ( $fs->is_plugin() && current_user_can( 'install_plugins' ) ) ||- ( $fs->is_theme() && current_user_can( 'install_themes' ) )- );-- $query_params = array_merge( $context_params, $_GET, array(- // Current plugin version.- 'plugin_version' => $fs->get_plugin_version(),- 'sdk_version' => WP_FS__SDK_VERSION,- 'is_premium' => $is_premium ? 'true' : 'false',- 'can_install' => $can_user_install ? 'true' : 'false',- 'return_url' => $return_url,- ) );-- $xdebug_session = fs_request_get( 'XDEBUG_SESSION' );- if ( false !== $xdebug_session ) {- $query_params['XDEBUG_SESSION'] = $xdebug_session;- }-- $view_params = array(- 'id' => $VARS['id'],- 'page' => strtolower( $fs->get_text_inline( 'Checkout', 'checkout' ) ) . ' ' . $fs->get_text_inline( 'PCI compliant', 'pci-compliant' ),- );- fs_require_once_template('secure-https-header.php', $view_params);-?>- <div id="fs_checkout" class="wrap fs-section fs-full-size-wrapper">- <div id="fs_frame"></div>- <script type="text/javascript">- // http://stackoverflow.com/questions/4583703/jquery-post-request-not-ajax- jQuery(function ($) {- $.extend({- form: function (url, data, method) {- if (method == null) method = 'POST';- if (data == null) data = {};-- var form = $('<form>').attr({- method: method,- action: url- }).css({- display: 'none'- });-- var addData = function (name, data) {- if ($.isArray(data)) {- for (var i = 0; i < data.length; i++) {- var value = data[i];- addData(name + '[]', value);- }- } else if (typeof data === 'object') {- for (var key in data) {- if (data.hasOwnProperty(key)) {- addData(name + '[' + key + ']', data[key]);- }- }- } else if (data != null) {- form.append($('<input>').attr({- type : 'hidden',- name : String(name),- value: String(data)- }));- }- };-- for (var key in data) {- if (data.hasOwnProperty(key)) {- addData(key, data[key]);- }- }-- return form.appendTo('body');- }- });- });-- (function ($) {- $(function () {-- var- // Keep track of the i-frame height.- frame_height = 800,- base_url = '<?php echo FS_CHECKOUT__ADDRESS ?>',- // Pass the parent page URL into the i-frame in a meaningful way (this URL could be- // passed via query string or hard coded into the child page, it depends on your needs).- src = base_url + '/?<?php echo http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href),- // Append the i-frame into the DOM.- frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>')- .appendTo('#fs_frame');-- FS.PostMessage.init(base_url, [frame[0]]);- FS.PostMessage.receiveOnce('height', function (data) {- var h = data.height;- if (!isNaN(h) && h > 0 && h != frame_height) {- frame_height = h;- frame.height(frame_height + 'px');-- FS.PostMessage.postScroll(frame[0]);- }- });-- FS.PostMessage.receiveOnce('install', function (data) {- var requestData = {- user_id : data.user.id,- user_secret_key : data.user.secret_key,- user_public_key : data.user.public_key,- install_id : data.install.id,- install_secret_key: data.install.secret_key,- install_public_key: data.install.public_key- };-- if (true === data.auto_install)- requestData.auto_install = true;-- // Post data to activation URL.- $.form('<?php echo fs_nonce_url( $fs->_get_admin_page_url( 'account', array(- 'fs_action' => $fs->get_unique_affix() . '_activate_new',- 'plugin_id' => $plugin_id- ) ), $fs->get_unique_affix() . '_activate_new' ) ?>', requestData).submit();- });-- FS.PostMessage.receiveOnce('pending_activation', function (data) {- var requestData = {- user_email : data.user_email,- support_email_address: data.support_email_address- };-- if (true === data.auto_install)- requestData.auto_install = true;-- $.form('<?php echo fs_nonce_url( $fs->_get_admin_page_url( 'account', array(- 'fs_action' => $fs->get_unique_affix() . '_activate_new',- 'plugin_id' => $plugin_id,- 'pending_activation' => true,- 'has_upgrade_context' => true,- ) ), $fs->get_unique_affix() . '_activate_new' ) ?>', requestData).submit();- });-- FS.PostMessage.receiveOnce('get_context', function () {- console.debug('receiveOnce', 'get_context');-- // If the user didn't connect his account with Freemius,- // once he accepts the Terms of Service and Privacy Policy,- // and then click the purchase button, the context information- // of the user will be shared with Freemius in order to complete the- // purchase workflow and activate the license for the right user.- <?php $install_data = array_merge( $fs->get_opt_in_params(),- array(- 'activation_url' => fs_nonce_url( $fs->_get_admin_page_url( '',- array(- 'fs_action' => $fs->get_unique_affix() . '_activate_new',- 'plugin_id' => $plugin_id,-- ) ),- $fs->get_unique_affix() . '_activate_new' )- ) ) ?>- FS.PostMessage.post('context', <?php echo json_encode( $install_data ) ?>, frame[0]);- });-- FS.PostMessage.receiveOnce('purchaseCompleted', <?php echo $fs->apply_filters('checkout/purchaseCompleted', 'function (data) {- console.log("checkout", "purchaseCompleted");- }') ?>);-- FS.PostMessage.receiveOnce('get_dimensions', function (data) {- console.debug('receiveOnce', 'get_dimensions');-- FS.PostMessage.post('dimensions', {- height : $(document.body).height(),- scrollTop: $(document).scrollTop()- }, frame[0]);- });-- var updateHeight = function () {- frame.css('min-height', $(document.body).height() + 'px');- };-- $(document).ready(updateHeight);-- $(window).resize(updateHeight);- });- })(jQuery);- </script>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + /** + * Note for WordPress.org Theme/Plugin reviewer: + * Freemius is an SDK for plugin and theme developers. Since the core + * of the SDK is relevant both for plugins and themes, for obvious reasons, + * we only develop and maintain one code base. + * + * This code (and page) will not run for wp.org themes (only plugins). + * + * In addition, this page loads an i-frame. We intentionally named it 'frame' + * so it will pass the "Theme Check" that is looking for the string "i" . "frame". + * + * UPDATE: + * After ongoing conversations with the WordPress.org TRT we received + * an official approval for including i-frames in the theme's WP Admin setting's + * page tab (the SDK will never add any i-frames on the sitefront). i-frames + * were never against the guidelines, but we wanted to get the team's blessings + * before we move forward. For the record, I got the final approval from + * Ulrich Pogson (@grapplerulrich), a team lead at the TRT during WordCamp + * Europe 2017 (June 16th, 2017). + * + * If you have any questions or need clarifications, please don't hesitate + * pinging me on slack, my username is @svovaf. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.2 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + wp_enqueue_script( 'jquery' ); + wp_enqueue_script( 'json2' ); + fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' ); + fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' ); + fs_enqueue_local_style( 'fs_common', '/admin/common.css' ); + + fs_enqueue_local_style( 'fs_checkout', '/admin/checkout.css' ); + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + $slug = $fs->get_slug(); + + $timestamp = time(); + + $context_params = array( + 'plugin_id' => $fs->get_id(), + 'public_key' => $fs->get_public_key(), + 'plugin_version' => $fs->get_plugin_version(), + 'mode' => 'dashboard', + 'trial' => fs_request_get_bool( 'trial' ), + 'is_ms' => ( fs_is_network_admin() && $fs->is_network_active() ), + ); + + $plan_id = fs_request_get( 'plan_id' ); + if ( FS_Plugin_Plan::is_valid_id( $plan_id ) ) { + $context_params['plan_id'] = $plan_id; + } + + $licenses = fs_request_get( 'licenses' ); + if ( $licenses === strval( intval( $licenses ) ) && $licenses > 0 ) { + $context_params['licenses'] = $licenses; + } + + $plugin_id = fs_request_get( 'plugin_id' ); + if ( ! FS_Plugin::is_valid_id( $plugin_id ) ) { + $plugin_id = $fs->get_id(); + } + + if ( $plugin_id == $fs->get_id() ) { + $is_premium = $fs->is_premium(); + + $bundle_id = $fs->get_bundle_id(); + if ( ! is_null( $bundle_id ) ) { + $context_params['bundle_id'] = $bundle_id; + } + } else { + // Identify the module code version of the checkout context module. + if ( $fs->is_addon_activated( $plugin_id ) ) { + $fs_addon = Freemius::get_instance_by_id( $plugin_id ); + $is_premium = $fs_addon->is_premium(); + } else { + // If add-on isn't activated assume the premium version isn't installed. + $is_premium = false; + } + } + + // Get site context secure params. + if ( $fs->is_registered() ) { + $site = $fs->get_site(); + + if ( $plugin_id != $fs->get_id() ) { + if ( $fs->is_addon_activated( $plugin_id ) ) { + $fs_addon = Freemius::get_instance_by_id( $plugin_id ); + $addon_site = $fs_addon->get_site(); + if ( is_object( $addon_site ) ) { + $site = $addon_site; + } + } + } + + $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params( + $site, + $timestamp, + 'checkout' + ) ); + } else { + $current_user = Freemius::_get_current_wp_user(); + + // Add site and user info to the request, this information + // is NOT being stored unless the user complete the purchase + // and agrees to the TOS. + $context_params = array_merge( $context_params, array( + 'user_firstname' => $current_user->user_firstname, + 'user_lastname' => $current_user->user_lastname, + 'user_email' => $current_user->user_email, + 'home_url' => home_url(), + ) ); + + $fs_user = Freemius::_get_user_by_email( $current_user->user_email ); + + if ( is_object( $fs_user ) && $fs_user->is_verified() ) { + $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params( + $fs_user, + $timestamp, + 'checkout' + ) ); + } + } + + if ( $fs->is_payments_sandbox() ) { + // Append plugin secure token for sandbox mode authentication. + $context_params['sandbox'] = FS_Security::instance()->get_secure_token( + $fs->get_plugin(), + $timestamp, + 'checkout' + ); + + /** + * @since 1.1.7.3 Add security timestamp for sandbox even for anonymous user. + */ + if ( empty( $context_params['s_ctx_ts'] ) ) { + $context_params['s_ctx_ts'] = $timestamp; + } + } + + $return_url = $fs->_get_sync_license_url( $plugin_id ); + + $can_user_install = ( + ( $fs->is_plugin() && current_user_can( 'install_plugins' ) ) || + ( $fs->is_theme() && current_user_can( 'install_themes' ) ) + ); + + $query_params = array_merge( $context_params, $_GET, array( + // Current plugin version. + 'plugin_version' => $fs->get_plugin_version(), + 'sdk_version' => WP_FS__SDK_VERSION, + 'is_premium' => $is_premium ? 'true' : 'false', + 'can_install' => $can_user_install ? 'true' : 'false', + 'return_url' => $return_url, + ) ); + + $xdebug_session = fs_request_get( 'XDEBUG_SESSION' ); + if ( false !== $xdebug_session ) { + $query_params['XDEBUG_SESSION'] = $xdebug_session; + } + + $view_params = array( + 'id' => $VARS['id'], + 'page' => strtolower( $fs->get_text_inline( 'Checkout', 'checkout' ) ) . ' ' . $fs->get_text_inline( 'PCI compliant', 'pci-compliant' ), + ); + fs_require_once_template('secure-https-header.php', $view_params); +?> + <div id="fs_checkout" class="wrap fs-section fs-full-size-wrapper"> + <div id="fs_frame"></div> + <script type="text/javascript"> + // http://stackoverflow.com/questions/4583703/jquery-post-request-not-ajax + jQuery(function ($) { + $.extend({ + form: function (url, data, method) { + if (method == null) method = 'POST'; + if (data == null) data = {}; + + var form = $('<form>').attr({ + method: method, + action: url + }).css({ + display: 'none' + }); + + var addData = function (name, data) { + if ($.isArray(data)) { + for (var i = 0; i < data.length; i++) { + var value = data[i]; + addData(name + '[]', value); + } + } else if (typeof data === 'object') { + for (var key in data) { + if (data.hasOwnProperty(key)) { + addData(name + '[' + key + ']', data[key]); + } + } + } else if (data != null) { + form.append($('<input>').attr({ + type : 'hidden', + name : String(name), + value: String(data) + })); + } + }; + + for (var key in data) { + if (data.hasOwnProperty(key)) { + addData(key, data[key]); + } + } + + return form.appendTo('body'); + } + }); + }); + + (function ($) { + $(function () { + + var + // Keep track of the i-frame height. + frame_height = 800, + base_url = '<?php echo FS_CHECKOUT__ADDRESS ?>', + // Pass the parent page URL into the i-frame in a meaningful way (this URL could be + // passed via query string or hard coded into the child page, it depends on your needs). + src = base_url + '/?<?php echo http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href), + // Append the i-frame into the DOM. + frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>') + .appendTo('#fs_frame'); + + FS.PostMessage.init(base_url, [frame[0]]); + FS.PostMessage.receiveOnce('height', function (data) { + var h = data.height; + if (!isNaN(h) && h > 0 && h != frame_height) { + frame_height = h; + frame.height(frame_height + 'px'); + + FS.PostMessage.postScroll(frame[0]); + } + }); + + FS.PostMessage.receiveOnce('install', function (data) { + var requestData = { + user_id : data.user.id, + user_secret_key : data.user.secret_key, + user_public_key : data.user.public_key, + install_id : data.install.id, + install_secret_key: data.install.secret_key, + install_public_key: data.install.public_key + }; + + if (true === data.auto_install) + requestData.auto_install = true; + + // Post data to activation URL. + $.form('<?php echo fs_nonce_url( $fs->_get_admin_page_url( 'account', array( + 'fs_action' => $fs->get_unique_affix() . '_activate_new', + 'plugin_id' => $plugin_id + ) ), $fs->get_unique_affix() . '_activate_new' ) ?>', requestData).submit(); + }); + + FS.PostMessage.receiveOnce('pending_activation', function (data) { + var requestData = { + user_email : data.user_email, + support_email_address: data.support_email_address + }; + + if (true === data.auto_install) + requestData.auto_install = true; + + $.form('<?php echo fs_nonce_url( $fs->_get_admin_page_url( 'account', array( + 'fs_action' => $fs->get_unique_affix() . '_activate_new', + 'plugin_id' => $plugin_id, + 'pending_activation' => true, + 'has_upgrade_context' => true, + ) ), $fs->get_unique_affix() . '_activate_new' ) ?>', requestData).submit(); + }); + + FS.PostMessage.receiveOnce('get_context', function () { + console.debug('receiveOnce', 'get_context'); + + // If the user didn't connect his account with Freemius, + // once he accepts the Terms of Service and Privacy Policy, + // and then click the purchase button, the context information + // of the user will be shared with Freemius in order to complete the + // purchase workflow and activate the license for the right user. + <?php $install_data = array_merge( $fs->get_opt_in_params(), + array( + 'activation_url' => fs_nonce_url( $fs->_get_admin_page_url( '', + array( + 'fs_action' => $fs->get_unique_affix() . '_activate_new', + 'plugin_id' => $plugin_id, + + ) ), + $fs->get_unique_affix() . '_activate_new' ) + ) ) ?> + FS.PostMessage.post('context', <?php echo json_encode( $install_data ) ?>, frame[0]); + }); + + FS.PostMessage.receiveOnce('purchaseCompleted', <?php echo $fs->apply_filters('checkout/purchaseCompleted', 'function (data) { + console.log("checkout", "purchaseCompleted"); + }') ?>); + + FS.PostMessage.receiveOnce('get_dimensions', function (data) { + console.debug('receiveOnce', 'get_dimensions'); + + FS.PostMessage.post('dimensions', { + height : $(document.body).height(), + scrollTop: $(document).scrollTop() + }, frame[0]); + }); + + var updateHeight = function () { + frame.css('min-height', $(document.body).height() + 'px'); + }; + + $(document).ready(updateHeight); + + $(window).resize(updateHeight); + }); + })(jQuery); + </script> </div>\ No newline at end of file
This diff contains only whitespace and line ending changes (Unix-style line endings replacing Windows-style). There are no actual code modifications, security fixes, or vulnerability changes. **Analysis Result:** No vulnerabilities detected in this diff. **Explanation:** The diff shows changes exclusively to line endings and indentation formatting: - Lines changed from Windows (CRLF) to Unix (LF) line endings - No functional code was modified - No security-relevant changes were made to logic, functions, or data handling - All PHP, JavaScript, and HTML code remains identical in functionality Since there are no code changes, there are no security vulnerabilities to analyze.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/clone-resolution-js.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/clone-resolution-js.php 2026-01-19 00:17:37.675046521 +0000@@ -1,89 +1,89 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.5.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-?>-<script type="text/javascript">- ( function( $ ) {- var $errorMessage = null;-- $( document ).ready( function() {- var $cloneResolutionNotice = $( 'div[data-id="clone_resolution_options_notice"], div[data-id="temporary_duplicate_notice"]' );-- if ( 0 === $cloneResolutionNotice.length ) {- return;- }-- $errorMessage = $cloneResolutionNotice.find( '#fs_clone_resolution_error_message' );-- /**- * Triggers an AJAX request when the license activation link or any of the buttons on the clone resolution options notice is clicked. The AJAX request will then handle the action the user has chosen.- */- $cloneResolutionNotice.on( 'click', '.button, #fs_temporary_duplicate_license_activation_link', function( evt ) {- evt.preventDefault();-- var $this = $( this );-- if ( $this.hasClass( 'disabled' ) ) {- return;- }-- var $body = $( 'body' ),- $optionsContainer = $this.parents( '.fs-clone-resolution-options-container' ),- cursor = $body.css( 'cursor' ),- beforeUnload = function() {- return '<?php fs_esc_js_echo_inline( 'Please wait', 'please-wait' ) ?>';- };-- $.ajax( {- // Get the parent options container from the child as `$cloneResolutionNotice` can have different AJAX URLs if both the manual clone resolution options and temporary duplicate notices are shown (for different subsites in a multisite network).- url : $optionsContainer.data( 'ajax-url' ),- method : 'POST',- data : {- action : '<?php echo $VARS['ajax_action'] ?>',- security : '<?php echo wp_create_nonce( $VARS['ajax_action'] ) ?>',- clone_action: $this.data( 'clone-action' ),- blog_id : $optionsContainer.data( 'blog-id' )- },- beforeSend: function() {- $body.css( { cursor: 'wait' } );-- $this.addClass( 'disabled' );-- if ( $this.attr( 'id' ) === 'fs_temporary_duplicate_license_activation_link' ) {- $this.append( '<i class="fs-ajax-spinner"></i>' );- }-- $( window ).on( 'beforeunload', beforeUnload );- },- success : function( resultObj ) {- $( window ).off( 'beforeunload', beforeUnload );-- if (- resultObj.data &&- resultObj.data.redirect_url &&- '' !== resultObj.data.redirect_url- ) {- window.location = resultObj.data.redirect_url;- } else {- window.location.reload();- }- },- complete : function() {- $body.css( { cursor: cursor } );- $this.removeClass( 'disabled' );-- $this.parent().find( '.fs-ajax-spinner' ).remove();- }- } );- } );- } );- } )( jQuery );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.5.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } +?> +<script type="text/javascript"> + ( function( $ ) { + var $errorMessage = null; + + $( document ).ready( function() { + var $cloneResolutionNotice = $( 'div[data-id="clone_resolution_options_notice"], div[data-id="temporary_duplicate_notice"]' ); + + if ( 0 === $cloneResolutionNotice.length ) { + return; + } + + $errorMessage = $cloneResolutionNotice.find( '#fs_clone_resolution_error_message' ); + + /** + * Triggers an AJAX request when the license activation link or any of the buttons on the clone resolution options notice is clicked. The AJAX request will then handle the action the user has chosen. + */ + $cloneResolutionNotice.on( 'click', '.button, #fs_temporary_duplicate_license_activation_link', function( evt ) { + evt.preventDefault(); + + var $this = $( this ); + + if ( $this.hasClass( 'disabled' ) ) { + return; + } + + var $body = $( 'body' ), + $optionsContainer = $this.parents( '.fs-clone-resolution-options-container' ), + cursor = $body.css( 'cursor' ), + beforeUnload = function() { + return '<?php fs_esc_js_echo_inline( 'Please wait', 'please-wait' ) ?>'; + }; + + $.ajax( { + // Get the parent options container from the child as `$cloneResolutionNotice` can have different AJAX URLs if both the manual clone resolution options and temporary duplicate notices are shown (for different subsites in a multisite network). + url : $optionsContainer.data( 'ajax-url' ), + method : 'POST', + data : { + action : '<?php echo $VARS['ajax_action'] ?>', + security : '<?php echo wp_create_nonce( $VARS['ajax_action'] ) ?>', + clone_action: $this.data( 'clone-action' ), + blog_id : $optionsContainer.data( 'blog-id' ) + }, + beforeSend: function() { + $body.css( { cursor: 'wait' } ); + + $this.addClass( 'disabled' ); + + if ( $this.attr( 'id' ) === 'fs_temporary_duplicate_license_activation_link' ) { + $this.append( '<i class="fs-ajax-spinner"></i>' ); + } + + $( window ).on( 'beforeunload', beforeUnload ); + }, + success : function( resultObj ) { + $( window ).off( 'beforeunload', beforeUnload ); + + if ( + resultObj.data && + resultObj.data.redirect_url && + '' !== resultObj.data.redirect_url + ) { + window.location = resultObj.data.redirect_url; + } else { + window.location.reload(); + } + }, + complete : function() { + $body.css( { cursor: cursor } ); + $this.removeClass( 'disabled' ); + + $this.parent().find( '.fs-ajax-spinner' ).remove(); + } + } ); + } ); + } ); + } )( jQuery ); </script>\ No newline at end of file
Vulnerability Existed: no No CWE Vulnerability Identified Old Code: Lines 1-89 (Unix LF line endings) Fixed Code: Lines 1-89 (Windows CRLF line endings) Explanation: This diff represents only a line ending change (LF to CRLF conversion). The actual code logic, security controls, and implementation remain identical between versions 1.2.11 and 1.2.12. No security vulnerabilities were introduced or fixed by this change. The code maintains proper security practices including: - CSRF protection via `wp_create_nonce()` - Proper AJAX action verification - Event handler validation - No XSS vulnerabilities in the JavaScript implementation The line ending normalization is a formatting change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/connect/index.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/connect/index.php 2026-01-19 00:17:37.675046521 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Security Vulnerabilities Detected - inc/freemius/templates/connect/index.php Explanation: The diff shows only a whitespace/formatting change to the file. The original file already contained the security-focused comment "Silence is golden" which is a standard WordPress security practice to prevent directory listing and information disclosure. The modification is a minor reformatting of the PHP opening tag and comment spacing, with no functional code changes. This is not a security fix but rather a code style adjustment. No vulnerabilities were introduced or fixed in this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/contact.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/contact.php 2026-01-19 00:17:37.675046521 +0000@@ -1,128 +1,128 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- /**- * Note for WordPress.org Theme/Plugin reviewer:- * Freemius is an SDK for plugin and theme developers. Since the core- * of the SDK is relevant both for plugins and themes, for obvious reasons,- * we only develop and maintain one code base.- *- * This code (and page) will not run for wp.org themes (only plugins).- *- * In addition, this page loads an i-frame. We intentionally named it 'frame'- * so it will pass the "Theme Check" that is looking for the string "i" . "frame".- *- * UPDATE:- * After ongoing conversations with the WordPress.org TRT we received- * an official approval for including i-frames in the theme's WP Admin setting's- * page tab (the SDK will never add any i-frames on the sitefront). i-frames- * were never against the guidelines, but we wanted to get the team's blessings- * before we move forward. For the record, I got the final approval from- * Ulrich Pogson (@grapplerulrich), a team lead at the TRT during WordCamp- * Europe 2017 (June 16th, 2017).- *- * If you have any questions or need clarifications, please don't hesitate- * pinging me on slack, my username is @svovaf.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- wp_enqueue_script( 'jquery' );- wp_enqueue_script( 'json2' );- fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' );- fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );- fs_enqueue_local_style( 'fs_checkout', '/admin/common.css' );-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );- $slug = $fs->get_slug();-- $context_params = array(- 'plugin_id' => $fs->get_id(),- 'plugin_public_key' => $fs->get_public_key(),- 'plugin_version' => $fs->get_plugin_version(),- );--- // Get site context secure params.- if ( $fs->is_registered() ) {- $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(- $fs->get_site(),- time(),- 'contact'- ) );- }-- $query_params = array_merge( $_GET, array_merge( $context_params, array(- 'plugin_version' => $fs->get_plugin_version(),- 'wp_login_url' => wp_login_url(),- 'site_url' => Freemius::get_unfiltered_site_url(),-// 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons",- ) ) );-- $view_params = array(- 'id' => $VARS['id'],- 'page' => strtolower( $fs->get_text_inline( 'Contact', 'contact' ) ),- );- fs_require_once_template('secure-https-header.php', $view_params);-- $has_tabs = $fs->_add_tabs_before_content();-- if ( $has_tabs ) {- $query_params['tabs'] = 'true';- }-?>- <div id="fs_contact" class="wrap fs-section fs-full-size-wrapper">- <div id="fs_frame"></div>- <script type="text/javascript">- (function ($) {- $(function () {-- var- // Keep track of the i-frame height.- frame_height = 800,- base_url = '<?php echo WP_FS__ADDRESS ?>',- src = base_url + '/contact/?<?php echo http_build_query($query_params) ?>#' + encodeURIComponent(document.location.href),-- // Append the i-frame into the DOM.- frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>')- .appendTo('#fs_frame');-- FS.PostMessage.init(base_url);- FS.PostMessage.receive('height', function (data) {- var h = data.height;- if (!isNaN(h) && h > 0 && h != frame_height) {- frame_height = h;- $('#fs_frame i' + 'frame').height(frame_height + 'px');- }- });- });- })(jQuery);- </script>- </div>-<?php- if ( $has_tabs ) {- $fs->_add_tabs_after_content();- }-- $params = array(- 'page' => 'contact',- 'module_id' => $fs->get_id(),- 'module_type' => $fs->get_module_type(),- 'module_slug' => $slug,- 'module_version' => $fs->get_plugin_version(),- );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + /** + * Note for WordPress.org Theme/Plugin reviewer: + * Freemius is an SDK for plugin and theme developers. Since the core + * of the SDK is relevant both for plugins and themes, for obvious reasons, + * we only develop and maintain one code base. + * + * This code (and page) will not run for wp.org themes (only plugins). + * + * In addition, this page loads an i-frame. We intentionally named it 'frame' + * so it will pass the "Theme Check" that is looking for the string "i" . "frame". + * + * UPDATE: + * After ongoing conversations with the WordPress.org TRT we received + * an official approval for including i-frames in the theme's WP Admin setting's + * page tab (the SDK will never add any i-frames on the sitefront). i-frames + * were never against the guidelines, but we wanted to get the team's blessings + * before we move forward. For the record, I got the final approval from + * Ulrich Pogson (@grapplerulrich), a team lead at the TRT during WordCamp + * Europe 2017 (June 16th, 2017). + * + * If you have any questions or need clarifications, please don't hesitate + * pinging me on slack, my username is @svovaf. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.2 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + wp_enqueue_script( 'jquery' ); + wp_enqueue_script( 'json2' ); + fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' ); + fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' ); + fs_enqueue_local_style( 'fs_checkout', '/admin/common.css' ); + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + $slug = $fs->get_slug(); + + $context_params = array( + 'plugin_id' => $fs->get_id(), + 'plugin_public_key' => $fs->get_public_key(), + 'plugin_version' => $fs->get_plugin_version(), + ); + + + // Get site context secure params. + if ( $fs->is_registered() ) { + $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params( + $fs->get_site(), + time(), + 'contact' + ) ); + } + + $query_params = array_merge( $_GET, array_merge( $context_params, array( + 'plugin_version' => $fs->get_plugin_version(), + 'wp_login_url' => wp_login_url(), + 'site_url' => Freemius::get_unfiltered_site_url(), +// 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons", + ) ) ); + + $view_params = array( + 'id' => $VARS['id'], + 'page' => strtolower( $fs->get_text_inline( 'Contact', 'contact' ) ), + ); + fs_require_once_template('secure-https-header.php', $view_params); + + $has_tabs = $fs->_add_tabs_before_content(); + + if ( $has_tabs ) { + $query_params['tabs'] = 'true'; + } +?> + <div id="fs_contact" class="wrap fs-section fs-full-size-wrapper"> + <div id="fs_frame"></div> + <script type="text/javascript"> + (function ($) { + $(function () { + + var + // Keep track of the i-frame height. + frame_height = 800, + base_url = '<?php echo WP_FS__ADDRESS ?>', + src = base_url + '/contact/?<?php echo http_build_query($query_params) ?>#' + encodeURIComponent(document.location.href), + + // Append the i-frame into the DOM. + frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>') + .appendTo('#fs_frame'); + + FS.PostMessage.init(base_url); + FS.PostMessage.receive('height', function (data) { + var h = data.height; + if (!isNaN(h) && h > 0 && h != frame_height) { + frame_height = h; + $('#fs_frame i' + 'frame').height(frame_height + 'px'); + } + }); + }); + })(jQuery); + </script> + </div> +<?php + if ( $has_tabs ) { + $fs->_add_tabs_after_content(); + } + + $params = array( + 'page' => 'contact', + 'module_id' => $fs->get_id(), + 'module_type' => $fs->get_module_type(), + 'module_slug' => $slug, + 'module_version' => $fs->get_plugin_version(), + ); fs_require_template( 'powered-by.php', $params );\ No newline at end of file
# Security Analysis Result **Vulnerability Existed: no** **No Vulnerabilities Detected** **Explanation:** The diff shows only whitespace and line-ending changes (converting line endings, likely from CRLF to LF). The actual code content remains identical between version 1.2.11 and 1.2.12. The code itself contains no new security fixes because no code logic was changed. The file structure, PHP logic, JavaScript iframe handling, and parameter processing all remain the same. **Note on Existing Code Concerns:** While this diff does not introduce or fix vulnerabilities, the code does contain a potential security pattern worth noting for broader context: the `$query_params` array merges unsanitized `$_GET` parameters directly into the iframe source URL (line 69). However, since this is pre-existing code and not changed in this diff, it falls outside the scope of this security fix analysis.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/debug/api-calls.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/debug/api-calls.php 2026-01-19 00:17:37.675046521 +0000@@ -1,155 +1,155 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.7.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- if ( class_exists( 'Freemius_Api_WordPress' ) ) {- $logger = Freemius_Api_WordPress::GetLogger();- } else {- $logger = array();- }-- $counters = array(- 'GET' => 0,- 'POST' => 0,- 'PUT' => 0,- 'DELETE' => 0- );-- $show_body = false;- foreach ( $logger as $log ) {- $counters[ $log['method'] ] ++;-- if ( ! is_null( $log['body'] ) ) {- $show_body = true;- }- }-- $pretty_print = $show_body && defined( 'JSON_PRETTY_PRINT' ) && version_compare( phpversion(), '5.3', '>=' );-- /**- * This template is used for debugging, therefore, when possible- * we'd like to prettify the output of a JSON encoded variable.- * This will only be executed when $pretty_print is `true`, and- * the var is `true` only for PHP 5.3 and higher. Due to the- * limitations of the current Theme Check, it throws an error- * that using the "options" parameter (the 2nd param) is not- * supported in PHP 5.2 and lower. Thus, we added this alias- * variable to work around that false-positive.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2.7- */- $encode = 'json_encode';-- $root_path_len = strlen( ABSPATH );-- $ms_text = fs_text_x_inline( 'ms', 'milliseconds' );-?>-<h1><?php fs_echo_inline( 'API' ) ?></h1>--<h2><span>Total Time:</span><?php echo Freemius_Debug_Bar_Panel::total_time() ?></h2>--<h2><span>Total Requests:</span><?php echo Freemius_Debug_Bar_Panel::requests_count() ?></h2>-<?php foreach ( $counters as $method => $count ) : ?>- <h2><span><?php echo $method ?>:</span><?php echo number_format( $count ) ?></h2>-<?php endforeach ?>-<table class="widefat">- <thead>- <tr>- <th>#</th>- <th><?php fs_esc_html_echo_inline( 'Method' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Code' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Length' ) ?></th>- <th><?php fs_esc_html_echo_x_inline( 'Path', 'as file/folder path' ) ?></th>- <?php if ( $show_body ) : ?>- <th><?php fs_esc_html_echo_inline( 'Body' ) ?></th>- <?php endif ?>- <th><?php fs_esc_html_echo_inline( 'Result' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Start' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'End' ) ?></th>- </tr>- </thead>- <tbody>- <?php foreach ( $logger as $log ) : ?>- <tr>- <td><?php echo $log['id'] ?>.</td>- <td><?php echo $log['method'] ?></td>- <td><?php echo $log['code'] ?></td>- <td><?php echo number_format( 100 * $log['total'], 2 ) . ' ' . $ms_text ?></td>- <td>- <?php- printf( '<a href="#" onclick="jQuery(this).parent().find(\'table\').toggle(); return false;">%s</a>',- $log['path']- );- ?>- <table class="widefat" style="display: none">- <tbody>- <?php for ( $i = 0, $bt = $log['backtrace'], $len = count( $bt ); $i < $len; $i ++ ) : ?>- <tr>- <td><?php echo( $len - $i ) ?></td>- <td><?php if ( isset( $bt[ $i ]['function'] ) ) {- echo ( isset( $bt[ $i ]['class'] ) ? $bt[ $i ]['class'] . $bt[ $i ]['type'] : '' ) . $bt[ $i ]['function'];- } ?></td>- <td><?php if ( isset( $bt[ $i ]['file'] ) ) {- echo substr( $bt[ $i ]['file'], $root_path_len ) . ':' . $bt[ $i ]['line'];- } ?></td>- </tr>- <?php endfor ?>- </tbody>- </table>- </td>- <?php if ( $show_body ) : ?>- <td>- <?php if ( 'GET' !== $log['method'] ) : ?>- <?php- $body = $log['body'];- printf(- '<a href="#" onclick="jQuery(this).parent().find(\'pre\').toggle(); return false;">%s</a>',- substr( $body, 0, 32 ) . ( 32 < strlen( $body ) ? '...' : '' )- );- if ( $pretty_print ) {- $body = $encode( json_decode( $log['body'] ), JSON_PRETTY_PRINT );- }- ?>- <pre style="display: none"><code><?php echo esc_html( $body ) ?></code></pre>- <?php endif ?>- </td>- <?php endif ?>- <td>- <?php- $result = $log['result'];-- $is_not_empty_result = ( is_string( $result ) && ! empty( $result ) );-- if ( $is_not_empty_result ) {- printf(- '<a href="#" onclick="jQuery(this).parent().find(\'pre\').toggle(); return false;">%s</a>',- substr( $result, 0, 32 ) . ( 32 < strlen( $result ) ? '...' : '' )- );- }-- if ( $is_not_empty_result && $pretty_print ) {- $decoded = json_decode( $result );- if ( ! is_null( $decoded ) ) {- $result = $encode( $decoded, JSON_PRETTY_PRINT );- }- } else {- $result = is_string( $result ) ? $result : json_encode( $result );- }- ?>- <pre<?php if ( $is_not_empty_result ) : ?> style="display: none"<?php endif ?>><code><?php echo esc_html( $result ) ?></code></pre>- </td>- <td><?php echo number_format( 100 * ( $log['start'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . $ms_text ?></td>- <td><?php echo number_format( 100 * ( $log['end'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . $ms_text ?></td>- </tr>- <?php endforeach ?>- </tbody>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.7.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + if ( class_exists( 'Freemius_Api_WordPress' ) ) { + $logger = Freemius_Api_WordPress::GetLogger(); + } else { + $logger = array(); + } + + $counters = array( + 'GET' => 0, + 'POST' => 0, + 'PUT' => 0, + 'DELETE' => 0 + ); + + $show_body = false; + foreach ( $logger as $log ) { + $counters[ $log['method'] ] ++; + + if ( ! is_null( $log['body'] ) ) { + $show_body = true; + } + } + + $pretty_print = $show_body && defined( 'JSON_PRETTY_PRINT' ) && version_compare( phpversion(), '5.3', '>=' ); + + /** + * This template is used for debugging, therefore, when possible + * we'd like to prettify the output of a JSON encoded variable. + * This will only be executed when $pretty_print is `true`, and + * the var is `true` only for PHP 5.3 and higher. Due to the + * limitations of the current Theme Check, it throws an error + * that using the "options" parameter (the 2nd param) is not + * supported in PHP 5.2 and lower. Thus, we added this alias + * variable to work around that false-positive. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.2.7 + */ + $encode = 'json_encode'; + + $root_path_len = strlen( ABSPATH ); + + $ms_text = fs_text_x_inline( 'ms', 'milliseconds' ); +?> +<h1><?php fs_echo_inline( 'API' ) ?></h1> + +<h2><span>Total Time:</span><?php echo Freemius_Debug_Bar_Panel::total_time() ?></h2> + +<h2><span>Total Requests:</span><?php echo Freemius_Debug_Bar_Panel::requests_count() ?></h2> +<?php foreach ( $counters as $method => $count ) : ?> + <h2><span><?php echo $method ?>:</span><?php echo number_format( $count ) ?></h2> +<?php endforeach ?> +<table class="widefat"> + <thead> + <tr> + <th>#</th> + <th><?php fs_esc_html_echo_inline( 'Method' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Code' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Length' ) ?></th> + <th><?php fs_esc_html_echo_x_inline( 'Path', 'as file/folder path' ) ?></th> + <?php if ( $show_body ) : ?> + <th><?php fs_esc_html_echo_inline( 'Body' ) ?></th> + <?php endif ?> + <th><?php fs_esc_html_echo_inline( 'Result' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Start' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'End' ) ?></th> + </tr> + </thead> + <tbody> + <?php foreach ( $logger as $log ) : ?> + <tr> + <td><?php echo $log['id'] ?>.</td> + <td><?php echo $log['method'] ?></td> + <td><?php echo $log['code'] ?></td> + <td><?php echo number_format( 100 * $log['total'], 2 ) . ' ' . $ms_text ?></td> + <td> + <?php + printf( '<a href="#" onclick="jQuery(this).parent().find(\'table\').toggle(); return false;">%s</a>', + $log['path'] + ); + ?> + <table class="widefat" style="display: none"> + <tbody> + <?php for ( $i = 0, $bt = $log['backtrace'], $len = count( $bt ); $i < $len; $i ++ ) : ?> + <tr> + <td><?php echo( $len - $i ) ?></td> + <td><?php if ( isset( $bt[ $i ]['function'] ) ) { + echo ( isset( $bt[ $i ]['class'] ) ? $bt[ $i ]['class'] . $bt[ $i ]['type'] : '' ) . $bt[ $i ]['function']; + } ?></td> + <td><?php if ( isset( $bt[ $i ]['file'] ) ) { + echo substr( $bt[ $i ]['file'], $root_path_len ) . ':' . $bt[ $i ]['line']; + } ?></td> + </tr> + <?php endfor ?> + </tbody> + </table> + </td> + <?php if ( $show_body ) : ?> + <td> + <?php if ( 'GET' !== $log['method'] ) : ?> + <?php + $body = $log['body']; + printf( + '<a href="#" onclick="jQuery(this).parent().find(\'pre\').toggle(); return false;">%s</a>', + substr( $body, 0, 32 ) . ( 32 < strlen( $body ) ? '...' : '' ) + ); + if ( $pretty_print ) { + $body = $encode( json_decode( $log['body'] ), JSON_PRETTY_PRINT ); + } + ?> + <pre style="display: none"><code><?php echo esc_html( $body ) ?></code></pre> + <?php endif ?> + </td> + <?php endif ?> + <td> + <?php + $result = $log['result']; + + $is_not_empty_result = ( is_string( $result ) && ! empty( $result ) ); + + if ( $is_not_empty_result ) { + printf( + '<a href="#" onclick="jQuery(this).parent().find(\'pre\').toggle(); return false;">%s</a>', + substr( $result, 0, 32 ) . ( 32 < strlen( $result ) ? '...' : '' ) + ); + } + + if ( $is_not_empty_result && $pretty_print ) { + $decoded = json_decode( $result ); + if ( ! is_null( $decoded ) ) { + $result = $encode( $decoded, JSON_PRETTY_PRINT ); + } + } else { + $result = is_string( $result ) ? $result : json_encode( $result ); + } + ?> + <pre<?php if ( $is_not_empty_result ) : ?> style="display: none"<?php endif ?>><code><?php echo esc_html( $result ) ?></code></pre> + </td> + <td><?php echo number_format( 100 * ( $log['start'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . $ms_text ?></td> + <td><?php echo number_format( 100 * ( $log['end'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . $ms_text ?></td> + </tr> + <?php endforeach ?> + </tbody> </table>\ No newline at end of file
Based on my analysis of the provided diff, here is the security assessment: **Analysis Result:** Vulnerability Existed: **no** The diff shows only whitespace/line ending changes (converting from Unix line endings to Windows line endings or vice versa). The actual code logic, structure, and security measures remain completely unchanged between versions 1.2.11 and 1.2.12. **Key Observations:** 1. All PHP code remains identical in functionality 2. All `esc_html()` escaping functions are present in both versions 3. All security functions like `fs_esc_html_echo_inline()` and `fs_esc_html_echo_x_inline()` remain unchanged 4. No code additions, deletions, or logical modifications exist 5. The diff contains only formatting/line ending changes (indicated by the "\ No newline at end of file" markers) **Conclusion:** Since no actual code changes were made between these versions—only whitespace/line ending normalization—there are no new security fixes to report and no vulnerabilities were introduced or remediated.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/debug/index.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/debug/index.php 2026-01-19 00:17:37.675046521 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Vulnerability Identified - inc/freemius/templates/debug/index.php Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: The diff shows only whitespace/formatting changes (likely tabs vs spaces normalization) with no functional code modifications. The file remains a blank PHP template that prevents directory listing, which is a security best practice. No vulnerabilities were introduced or fixed in this change - it is purely a formatting adjustment to the existing secure implementation.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/debug/logger.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/debug/logger.php 2026-01-19 00:17:37.675046521 +0000@@ -1,66 +1,66 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.7.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- $log_book = FS_Logger::get_log();-?>-<h1><?php fs_echo_inline( 'Log' ) ?></h1>--<table class="widefat" style="font-size: 11px;">- <thead>- <tr>- <th>#</th>- <th><?php fs_esc_html_echo_inline( 'ID', 'id' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Type' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Function' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Message' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'File' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Timestamp' ) ?></th>- </tr>- </thead>- <tbody>-- <?php $i = 0;- foreach ( $log_book as $log ) : ?>- <?php- /**- * @var FS_Logger $logger- */- $logger = $log['logger'];- ?>- <tr<?php if ( $i % 2 ) {- echo ' class="alternate"';- } ?>>- <td><?php echo $log['cnt'] ?>.</td>- <td><?php echo $logger->get_id() ?></td>- <td><?php echo $log['log_type'] ?></td>- <td><b><code style="color: blue;"><?php echo ( ! empty( $log['class'] ) ? $log['class'] . $log['type'] : '' ) . $log['function'] ?></code></b></td>- <td>- <?php- printf(- '<a href="#" style="color: darkorange !important;" onclick="jQuery(this).parent().find(\'div\').toggle(); return false;"><nobr>%s</nobr></a>',- esc_html( substr( $log['msg'], 0, 32 ) ) . ( 32 < strlen( $log['msg'] ) ? '...' : '' )- );- ?>- <div style="display: none;">- <b style="color: darkorange;"><?php echo esc_html( $log['msg'] ) ?></b>- </div>- </td>- <td><?php- if ( isset( $log['file'] ) ) {- echo substr( $log['file'], $logger->get_file() ) . ':' . $log['line'];- }- ?></td>- <td><?php echo number_format( 100 * ( $log['timestamp'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . fs_text_x_inline( 'ms', 'milliseconds' ) ?></td>- </tr>- <?php $i ++; endforeach ?>- </tbody>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.7.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + $log_book = FS_Logger::get_log(); +?> +<h1><?php fs_echo_inline( 'Log' ) ?></h1> + +<table class="widefat" style="font-size: 11px;"> + <thead> + <tr> + <th>#</th> + <th><?php fs_esc_html_echo_inline( 'ID', 'id' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Type' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Function' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Message' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'File' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Timestamp' ) ?></th> + </tr> + </thead> + <tbody> + + <?php $i = 0; + foreach ( $log_book as $log ) : ?> + <?php + /** + * @var FS_Logger $logger + */ + $logger = $log['logger']; + ?> + <tr<?php if ( $i % 2 ) { + echo ' class="alternate"'; + } ?>> + <td><?php echo $log['cnt'] ?>.</td> + <td><?php echo $logger->get_id() ?></td> + <td><?php echo $log['log_type'] ?></td> + <td><b><code style="color: blue;"><?php echo ( ! empty( $log['class'] ) ? $log['class'] . $log['type'] : '' ) . $log['function'] ?></code></b></td> + <td> + <?php + printf( + '<a href="#" style="color: darkorange !important;" onclick="jQuery(this).parent().find(\'div\').toggle(); return false;"><nobr>%s</nobr></a>', + esc_html( substr( $log['msg'], 0, 32 ) ) . ( 32 < strlen( $log['msg'] ) ? '...' : '' ) + ); + ?> + <div style="display: none;"> + <b style="color: darkorange;"><?php echo esc_html( $log['msg'] ) ?></b> + </div> + </td> + <td><?php + if ( isset( $log['file'] ) ) { + echo substr( $log['file'], $logger->get_file() ) . ':' . $log['line']; + } + ?></td> + <td><?php echo number_format( 100 * ( $log['timestamp'] - WP_FS__SCRIPT_START_TIME ), 2 ) . ' ' . fs_text_x_inline( 'ms', 'milliseconds' ) ?></td> + </tr> + <?php $i ++; endforeach ?> + </tbody> </table>\ No newline at end of file
Analyzing the provided diff for security vulnerabilities:
---
**Vulnerability Existed:** no
**No Security Vulnerabilities Detected**
**Explanation:**
This diff shows only formatting changes (line ending conversion from CRLF to LF). The actual code content remains identical between versions 1.2.11 and 1.2.12.
The code itself contains potential security concerns that existed in both versions:
1. **Inline JavaScript in HTML attributes (line 50):** The `onclick="jQuery(this).parent().find('div').toggle(); return false;"` is vulnerable to XSS if `$log['msg']` contains malicious content. However, this is mitigated by the `esc_html()` call on line 54.
2. **Direct output without escaping (lines 43-46):** Values like `$log['cnt']`, `$logger->get_id()`, `$log['log_type']`, and `$log['function']` are echoed without escaping. This could be XSS vulnerable if these values contain user-controlled or untrusted data.
3. **Unescaped file path output (line 58):** The `$log['file']` and `$log['line']` are output without escaping.
However, since these vulnerabilities existed in **both versions** and the diff only changes line endings (no code logic changes), there are **no new security fixes introduced in this update**, nor were any vulnerabilities introduced. The security posture remains unchanged.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/debug/plugins-themes-sync.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/debug/plugins-themes-sync.php 2026-01-19 00:17:37.675046521 +0000@@ -1,76 +1,76 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.7.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- $fs_options = FS_Options::instance( WP_FS__ACCOUNTS_OPTION_NAME, true );- $all_plugins = $fs_options->get_option( 'all_plugins' );- $all_themes = $fs_options->get_option( 'all_themes' );-- /* translators: %s: time period (e.g. In "2 hours") */- $in_x_text = fs_text_inline( 'In %s', 'in-x' );- /* translators: %s: time period (e.g. "2 hours" ago) */- $x_ago_text = fs_text_inline( '%s ago', 'x-ago' );- $sec_text = fs_text_x_inline( 'sec', 'seconds' );-?>-<h1><?php fs_esc_html_echo_inline( 'Plugins & Themes Sync', 'plugins-themes-sync' ) ?></h1>-<table class="widefat">- <thead>- <tr>- <th></th>- <th><?php fs_esc_html_echo_inline( 'Total', 'total' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Last', 'last' ) ?></th>- </tr>- </thead>- <tbody>- <?php if ( is_object( $all_plugins ) ) : ?>- <tr>- <td><?php fs_esc_html_echo_inline( 'Plugins', 'plugins' ) ?></td>- <td><?php echo count( $all_plugins->plugins ) ?></td>- <td><?php- if ( isset( $all_plugins->timestamp ) && is_numeric( $all_plugins->timestamp ) ) {- $diff = abs( WP_FS__SCRIPT_START_TIME - $all_plugins->timestamp );- $human_diff = ( $diff < MINUTE_IN_SECONDS ) ?- $diff . ' ' . $sec_text :- human_time_diff( WP_FS__SCRIPT_START_TIME, $all_plugins->timestamp );-- echo esc_html( sprintf(- ( ( WP_FS__SCRIPT_START_TIME < $all_plugins->timestamp ) ?- $in_x_text :- $x_ago_text ),- $human_diff- ) );- }- ?></td>- </tr>- <?php endif ?>- <?php if ( is_object( $all_themes ) ) : ?>- <tr>- <td><?php fs_esc_html_echo_inline( 'Themes', 'themes' ) ?></td>- <td><?php echo count( $all_themes->themes ) ?></td>- <td><?php- if ( isset( $all_themes->timestamp ) && is_numeric( $all_themes->timestamp ) ) {- $diff = abs( WP_FS__SCRIPT_START_TIME - $all_themes->timestamp );- $human_diff = ( $diff < MINUTE_IN_SECONDS ) ?- $diff . ' ' . $sec_text :- human_time_diff( WP_FS__SCRIPT_START_TIME, $all_themes->timestamp );-- echo esc_html( sprintf(- ( ( WP_FS__SCRIPT_START_TIME < $all_themes->timestamp ) ?- $in_x_text :- $x_ago_text ),- $human_diff- ) );- }- ?></td>- </tr>- <?php endif ?>- </tbody>-</table>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.7.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + $fs_options = FS_Options::instance( WP_FS__ACCOUNTS_OPTION_NAME, true ); + $all_plugins = $fs_options->get_option( 'all_plugins' ); + $all_themes = $fs_options->get_option( 'all_themes' ); + + /* translators: %s: time period (e.g. In "2 hours") */ + $in_x_text = fs_text_inline( 'In %s', 'in-x' ); + /* translators: %s: time period (e.g. "2 hours" ago) */ + $x_ago_text = fs_text_inline( '%s ago', 'x-ago' ); + $sec_text = fs_text_x_inline( 'sec', 'seconds' ); +?> +<h1><?php fs_esc_html_echo_inline( 'Plugins & Themes Sync', 'plugins-themes-sync' ) ?></h1> +<table class="widefat"> + <thead> + <tr> + <th></th> + <th><?php fs_esc_html_echo_inline( 'Total', 'total' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Last', 'last' ) ?></th> + </tr> + </thead> + <tbody> + <?php if ( is_object( $all_plugins ) ) : ?> + <tr> + <td><?php fs_esc_html_echo_inline( 'Plugins', 'plugins' ) ?></td> + <td><?php echo count( $all_plugins->plugins ) ?></td> + <td><?php + if ( isset( $all_plugins->timestamp ) && is_numeric( $all_plugins->timestamp ) ) { + $diff = abs( WP_FS__SCRIPT_START_TIME - $all_plugins->timestamp ); + $human_diff = ( $diff < MINUTE_IN_SECONDS ) ? + $diff . ' ' . $sec_text : + human_time_diff( WP_FS__SCRIPT_START_TIME, $all_plugins->timestamp ); + + echo esc_html( sprintf( + ( ( WP_FS__SCRIPT_START_TIME < $all_plugins->timestamp ) ? + $in_x_text : + $x_ago_text ), + $human_diff + ) ); + } + ?></td> + </tr> + <?php endif ?> + <?php if ( is_object( $all_themes ) ) : ?> + <tr> + <td><?php fs_esc_html_echo_inline( 'Themes', 'themes' ) ?></td> + <td><?php echo count( $all_themes->themes ) ?></td> + <td><?php + if ( isset( $all_themes->timestamp ) && is_numeric( $all_themes->timestamp ) ) { + $diff = abs( WP_FS__SCRIPT_START_TIME - $all_themes->timestamp ); + $human_diff = ( $diff < MINUTE_IN_SECONDS ) ? + $diff . ' ' . $sec_text : + human_time_diff( WP_FS__SCRIPT_START_TIME, $all_themes->timestamp ); + + echo esc_html( sprintf( + ( ( WP_FS__SCRIPT_START_TIME < $all_themes->timestamp ) ? + $in_x_text : + $x_ago_text ), + $human_diff + ) ); + } + ?></td> + </tr> + <?php endif ?> + </tbody> +</table>
Based on my analysis of the provided diff for the file `inc/freemius/templates/debug/plugins-themes-sync.php`, the changes are **line ending conversions only** (from Unix LF to Windows CRLF or vice versa). There are no functional code changes. **Analysis Result:** Vulnerability Existed: no No CWE applicable - No functional code changes detected Old Code: (Same as new code - only whitespace/line ending differences) Fixed Code: (Same as old code - only whitespace/line ending differences) Explanation: This diff contains only line ending changes (CRLF vs LF). The functional code remains identical between versions 1.2.11 and 1.2.12. All security measures present in the original code are maintained: - Proper use of `esc_html()` and `fs_esc_html_echo_inline()` for output escaping - Type checking with `is_object()` and `is_numeric()` - Use of WordPress sanitization functions (`human_time_diff()`) - Proper use of translation functions No security vulnerabilities were introduced or fixed in this update, as no functional changes were made.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/debug/scheduled-crons.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/debug/scheduled-crons.php 2026-01-19 00:17:37.675046521 +0000@@ -1,136 +1,136 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.7.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- $fs_options = FS_Options::instance( WP_FS__ACCOUNTS_OPTION_NAME, true );- $scheduled_crons = array();-- $module_types = array(- WP_FS__MODULE_TYPE_PLUGIN,- WP_FS__MODULE_TYPE_THEME- );-- foreach ( $module_types as $module_type ) {- $modules = fs_get_entities( $fs_options->get_option( $module_type . 's' ), FS_Plugin::get_class_name() );- if ( is_array( $modules ) && count( $modules ) > 0 ) {- foreach ( $modules as $slug => $data ) {- if ( WP_FS__MODULE_TYPE_THEME === $module_type ) {- $current_theme = wp_get_theme();- $is_active = ( $current_theme->stylesheet === $data->file );- } else {- $is_active = is_plugin_active( $data->file );- }-- /**- * @author Vova Feldman- *- * @since 1.2.1 Don't load data from inactive modules.- */- if ( $is_active ) {- $fs = freemius( $data->id );-- $next_execution = $fs->next_sync_cron();- $last_execution = $fs->last_sync_cron();-- if ( false !== $next_execution ) {- $scheduled_crons[ $slug ][] = array(- 'name' => $fs->get_plugin_name(),- 'slug' => $slug,- 'module_type' => $fs->get_module_type(),- 'type' => 'sync_cron',- 'last' => $last_execution,- 'next' => $next_execution,- );- }-- $next_install_execution = $fs->next_install_sync();- $last_install_execution = $fs->last_install_sync();-- if (false !== $next_install_execution ||- false !== $last_install_execution- ) {- $scheduled_crons[ $slug ][] = array(- 'name' => $fs->get_plugin_name(),- 'slug' => $slug,- 'module_type' => $fs->get_module_type(),- 'type' => 'install_sync',- 'last' => $last_install_execution,- 'next' => $next_install_execution,- );- }- }- }- }- }-- $sec_text = fs_text_x_inline( 'sec', 'seconds' );-?>-<h1><?php fs_esc_html_echo_inline( 'Scheduled Crons' ) ?></h1>-<table class="widefat">- <thead>- <tr>- <th><?php fs_esc_html_echo_inline( 'Slug' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Module' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Module Type' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Cron Type' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Last' ) ?></th>- <th><?php fs_esc_html_echo_inline( 'Next' ) ?></th>- </tr>- </thead>- <tbody>- <?php- /* translators: %s: time period (e.g. In "2 hours") */- $in_x_text = fs_text_inline( 'In %s', 'in-x' );- /* translators: %s: time period (e.g. "2 hours" ago) */- $x_ago_text = fs_text_inline( '%s ago', 'x-ago' );- ?>- <?php foreach ( $scheduled_crons as $slug => $crons ) : ?>- <?php foreach ( $crons as $cron ) : ?>- <tr>- <td><?php echo $slug ?></td>- <td><?php echo $cron['name'] ?></td>- <td><?php echo $cron['module_type'] ?></td>- <td><?php echo $cron['type'] ?></td>- <td><?php- if ( is_numeric( $cron['last'] ) ) {- $diff = abs( WP_FS__SCRIPT_START_TIME - $cron['last'] );- $human_diff = ( $diff < MINUTE_IN_SECONDS ) ?- $diff . ' ' . $sec_text :- human_time_diff( WP_FS__SCRIPT_START_TIME, $cron['last'] );-- echo esc_html( sprintf(- ( ( WP_FS__SCRIPT_START_TIME < $cron['last'] ) ?- $in_x_text :- $x_ago_text ),- $human_diff- ) );- }- ?></td>- <td><?php- if ( is_numeric( $cron['next'] ) ) {- $diff = abs( WP_FS__SCRIPT_START_TIME - $cron['next'] );- $human_diff = ( $diff < MINUTE_IN_SECONDS ) ?- $diff . ' ' . $sec_text :- human_time_diff( WP_FS__SCRIPT_START_TIME, $cron['next'] );-- echo esc_html( sprintf(- ( ( WP_FS__SCRIPT_START_TIME < $cron['next'] ) ?- $in_x_text :- $x_ago_text ),- $human_diff- ) );- }- ?></td>- </tr>- <?php endforeach ?>- <?php endforeach ?>- </tbody>-</table>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.7.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + $fs_options = FS_Options::instance( WP_FS__ACCOUNTS_OPTION_NAME, true ); + $scheduled_crons = array(); + + $module_types = array( + WP_FS__MODULE_TYPE_PLUGIN, + WP_FS__MODULE_TYPE_THEME + ); + + foreach ( $module_types as $module_type ) { + $modules = fs_get_entities( $fs_options->get_option( $module_type . 's' ), FS_Plugin::get_class_name() ); + if ( is_array( $modules ) && count( $modules ) > 0 ) { + foreach ( $modules as $slug => $data ) { + if ( WP_FS__MODULE_TYPE_THEME === $module_type ) { + $current_theme = wp_get_theme(); + $is_active = ( $current_theme->stylesheet === $data->file ); + } else { + $is_active = is_plugin_active( $data->file ); + } + + /** + * @author Vova Feldman + * + * @since 1.2.1 Don't load data from inactive modules. + */ + if ( $is_active ) { + $fs = freemius( $data->id ); + + $next_execution = $fs->next_sync_cron(); + $last_execution = $fs->last_sync_cron(); + + if ( false !== $next_execution ) { + $scheduled_crons[ $slug ][] = array( + 'name' => $fs->get_plugin_name(), + 'slug' => $slug, + 'module_type' => $fs->get_module_type(), + 'type' => 'sync_cron', + 'last' => $last_execution, + 'next' => $next_execution, + ); + } + + $next_install_execution = $fs->next_install_sync(); + $last_install_execution = $fs->last_install_sync(); + + if (false !== $next_install_execution || + false !== $last_install_execution + ) { + $scheduled_crons[ $slug ][] = array( + 'name' => $fs->get_plugin_name(), + 'slug' => $slug, + 'module_type' => $fs->get_module_type(), + 'type' => 'install_sync', + 'last' => $last_install_execution, + 'next' => $next_install_execution, + ); + } + } + } + } + } + + $sec_text = fs_text_x_inline( 'sec', 'seconds' ); +?> +<h1><?php fs_esc_html_echo_inline( 'Scheduled Crons' ) ?></h1> +<table class="widefat"> + <thead> + <tr> + <th><?php fs_esc_html_echo_inline( 'Slug' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Module' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Module Type' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Cron Type' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Last' ) ?></th> + <th><?php fs_esc_html_echo_inline( 'Next' ) ?></th> + </tr> + </thead> + <tbody> + <?php + /* translators: %s: time period (e.g. In "2 hours") */ + $in_x_text = fs_text_inline( 'In %s', 'in-x' ); + /* translators: %s: time period (e.g. "2 hours" ago) */ + $x_ago_text = fs_text_inline( '%s ago', 'x-ago' ); + ?> + <?php foreach ( $scheduled_crons as $slug => $crons ) : ?> + <?php foreach ( $crons as $cron ) : ?> + <tr> + <td><?php echo $slug ?></td> + <td><?php echo $cron['name'] ?></td> + <td><?php echo $cron['module_type'] ?></td> + <td><?php echo $cron['type'] ?></td> + <td><?php + if ( is_numeric( $cron['last'] ) ) { + $diff = abs( WP_FS__SCRIPT_START_TIME - $cron['last'] ); + $human_diff = ( $diff < MINUTE_IN_SECONDS ) ? + $diff . ' ' . $sec_text : + human_time_diff( WP_FS__SCRIPT_START_TIME, $cron['last'] ); + + echo esc_html( sprintf( + ( ( WP_FS__SCRIPT_START_TIME < $cron['last'] ) ? + $in_x_text : + $x_ago_text ), + $human_diff + ) ); + } + ?></td> + <td><?php + if ( is_numeric( $cron['next'] ) ) { + $diff = abs( WP_FS__SCRIPT_START_TIME - $cron['next'] ); + $human_diff = ( $diff < MINUTE_IN_SECONDS ) ? + $diff . ' ' . $sec_text : + human_time_diff( WP_FS__SCRIPT_START_TIME, $cron['next'] ); + + echo esc_html( sprintf( + ( ( WP_FS__SCRIPT_START_TIME < $cron['next'] ) ? + $in_x_text : + $x_ago_text ), + $human_diff + ) ); + } + ?></td> + </tr> + <?php endforeach ?> + <?php endforeach ?> + </tbody> +</table>
Vulnerability Existed: no Explanation: This diff shows only whitespace and line ending changes (converting from Unix LF to Windows CRLF line endings, or vice versa). The actual code logic, structure, and security mechanisms remain identical between the two versions. The file contains no security vulnerabilities in either version: - All user-controlled output (slug, name, module_type, type) is properly escaped using `esc_html()` - Numeric values are validated with `is_numeric()` before use - The code accesses only internally-managed data structures from the WordPress options table - No SQL queries, file operations, or external data sources are accessed without proper sanitization The change is purely formatting and does not introduce, fix, or relate to any security issue.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/email.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/email.php 2026-01-19 00:17:37.675046521 +0000@@ -1,49 +1,49 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.1- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- */- $sections = $VARS['sections'];-?>-<table>- <?php- foreach ( $sections as $section_id => $section ) {- ?>- <thead>- <tr><th colspan="2" style="text-align: left; background: #333; color: #fff; padding: 5px;"><?php echo esc_html($section['title']) ?></th></tr>- </thead>- <tbody>- <?php- foreach ( $section['rows'] as $row_id => $row ) {- $col_count = count( $row );- ?>- <tr>- <?php- if ( 1 === $col_count ) { ?>- <td style="vertical-align: top;" colspan="2"><?php echo $row[0] ?></td>- <?php- } else { ?>- <td style="vertical-align: top;"><b><?php echo esc_html($row[0]) ?>:</b></td>- <td><?php echo $row[1]; ?></td>- <?php- }- ?>- </tr>- <?php- }- ?>- </tbody>- <?php- }- ?>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.1 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + */ + $sections = $VARS['sections']; +?> +<table> + <?php + foreach ( $sections as $section_id => $section ) { + ?> + <thead> + <tr><th colspan="2" style="text-align: left; background: #333; color: #fff; padding: 5px;"><?php echo esc_html($section['title']) ?></th></tr> + </thead> + <tbody> + <?php + foreach ( $section['rows'] as $row_id => $row ) { + $col_count = count( $row ); + ?> + <tr> + <?php + if ( 1 === $col_count ) { ?> + <td style="vertical-align: top;" colspan="2"><?php echo $row[0] ?></td> + <?php + } else { ?> + <td style="vertical-align: top;"><b><?php echo esc_html($row[0]) ?>:</b></td> + <td><?php echo $row[1]; ?></td> + <?php + } + ?> + </tr> + <?php + } + ?> + </tbody> + <?php + } + ?> </table>\ No newline at end of file
Vulnerability Existed: yes FALSE POSITIVE Cross-Site Scripting (XSS) - CWE-79 - inc/freemius/templates/email.php - Line 34 Old Code: ```php <td style="vertical-align: top;" colspan="2"><?php echo $row[0] ?></td> ``` Fixed Code: ```php <td style="vertical-align: top;" colspan="2"><?php echo $row[0] ?></td> ``` Explanation: This diff appears to only contain whitespace/line ending changes (CRLF to LF conversion). However, there is an actual vulnerability present in the code that was NOT fixed: Line 34 contains `<?php echo $row[0] ?>` without any escaping function, while similar output on line 37 uses `esc_html()`. The `$row[0]` value is user-controlled data that should be escaped to prevent XSS attacks. This vulnerability existed in version 1.2.11 and continues to exist in version 1.2.12 since the diff shows no actual code logic changes - only formatting changes. Additionally, line 38 contains `<?php echo $row[1]; ?>` which also lacks proper escaping and represents the same XSS vulnerability.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/affiliation.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/affiliation.php 2026-01-19 00:17:37.675046521 +0000@@ -1,518 +1,518 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.3- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- * @var string $plugin_title- */- $fs = freemius( $VARS['id'] );- $plugin_title = $VARS['plugin_title'];-- $slug = $fs->get_slug();-- $user = $fs->get_user();- $affiliate = $fs->get_affiliate();- $affiliate_terms = $fs->get_affiliate_terms();-- $module_type = $fs->is_plugin() ?- WP_FS__MODULE_TYPE_PLUGIN :- WP_FS__MODULE_TYPE_THEME;-- $commission = $affiliate_terms->get_formatted_commission();-- $readonly = false;- $is_affiliate = is_object( $affiliate );- $is_pending_affiliate = false;- $email_address = ( is_object( $user ) ?- $user->email :- '' );- $full_name = ( is_object( $user ) ?- $user->get_name() :- '' );- $paypal_email_address = '';- $domain = '';- $extra_domains = array();- $promotion_method_social_media = false;- $promotion_method_mobile_apps = false;- $statistics_information = false;- $promotion_method_description = false;- $members_dashboard_login_url = 'https://users.freemius.com/login';-- $affiliate_application_data = $fs->get_affiliate_application_data();-- if ( $is_affiliate && $affiliate->is_pending() ) {- $readonly = 'readonly';- $is_pending_affiliate = true;-- $paypal_email_address = $affiliate->paypal_email;- $domain = $affiliate->domain;- $statistics_information = $affiliate_application_data['stats_description'];- $promotion_method_description = $affiliate_application_data['promotion_method_description'];-- if ( ! empty( $affiliate_application_data['additional_domains'] ) ) {- $extra_domains = $affiliate_application_data['additional_domains'];- }-- if ( ! empty( $affiliate_application_data['promotion_methods'] ) ) {- $promotion_methods = explode( ',', $affiliate_application_data['promotion_methods'] );- $promotion_method_social_media = in_array( 'social_media', $promotion_methods );- $promotion_method_mobile_apps = in_array( 'mobile_apps', $promotion_methods );- }- } else {- if ( ! is_object( $user ) ) {- $current_user = Freemius::_get_current_wp_user();- $full_name = trim( $current_user->user_firstname . ' ' . $current_user->user_lastname );- $email_address = $current_user->user_email;- }-- $domain = Freemius::get_unfiltered_site_url( null, true );- }-- $affiliate_tracking = 30;-- if ( is_object( $affiliate_terms ) ) {- $affiliate_tracking = ( ! is_null( $affiliate_terms->cookie_days ) ?- ( $affiliate_terms->cookie_days . '-day' ) :- fs_text_inline( 'Non-expiring', 'non-expiring', $slug ) );- }-- $apply_to_become_affiliate_text = fs_text_inline( 'Apply to become an affiliate', 'apply-to-become-an-affiliate', $slug );-- $module_id = $fs->get_id();- $affiliate_program_terms_url = "https://freemius.com/plugin/{$module_id}/{$slug}/legal/affiliate-program/";-- $has_tabs = $fs->_add_tabs_before_content();-?>-<div id="fs_affiliation_content_wrapper" class="wrap">- <form method="post" action="">- <div id="poststuff">- <div class="postbox">- <div class="inside">- <div id="messages">- <div id="error_message" class="error" style="display: none">- <p><strong></strong></p>- </div>- <div id="message" class="updated" style="display: none">- <p><strong></strong></p>- </div>- <?php if ( $is_affiliate ) : ?>- <?php if ( $affiliate->is_active() ) : ?>- <div class="updated">- <p><strong><?php- echo sprintf(- fs_esc_html_inline( "Your affiliate application for %s has been accepted! Log in to your affiliate area at: %s.", 'affiliate-application-accepted', $slug ),- $plugin_title,- sprintf(- '<a href="%s" target="_blank" rel="noopener">%s</a>',- $members_dashboard_login_url,- $members_dashboard_login_url- )- );- ?></strong></p>- </div>- <?php else : ?>- <?php- $message_text = '';-- if ( $is_pending_affiliate ) {- $message_text = fs_text_inline( "Thank you for applying for our affiliate program, we'll review your details during the next 14 days and will get back to you with further information.", 'affiliate-application-thank-you', $slug );- $message_container_class = 'updated';- } else if ( $affiliate->is_suspended() ) {- $message_text = fs_text_inline( 'Your affiliation account was temporarily suspended.', 'affiliate-account-suspended', $slug );- $message_container_class = 'notice notice-warning';- } else if ( $affiliate->is_rejected() ) {- $message_text = fs_text_inline( "Thank you for applying for our affiliate program, unfortunately, we've decided at this point to reject your application. Please try again in 30 days.", 'affiliate-application-rejected', $slug );- $message_container_class = 'error';- } else if ( $affiliate->is_blocked() ) {- $message_text = fs_text_inline( 'Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support.', 'affiliate-account-blocked', $slug );- $message_container_class = 'error';- }- ?>- <div class="<?php echo $message_container_class ?>">- <p><strong><?php echo esc_html( $message_text ) ?></strong></p>- </div>- <?php endif ?>- <?php endif ?>- </div>- <div class="entry-content">- <?php if ( ! $is_affiliate ) : ?>- <div id="application_messages_container">- <p><?php echo esc_html( sprintf( fs_text_inline( 'Like the %s? Become our ambassador and earn cash ;-)', 'become-an-ambassador', $slug ), $module_type ) ) ?></p>- <p><?php echo esc_html( sprintf( fs_text_inline( 'Refer new customers to our %s and earn %s commission on each successful sale you refer!', 'refer-new-customers', $slug ), $module_type, $commission ) ) ?></p>- </div>- <?php endif ?>- <h3><?php fs_esc_html_echo_inline( 'Program Summary', 'program-summary', $slug ) ?></h3>- <ul>- <li><?php echo esc_html( sprintf( fs_text_inline( '%s commission when a customer purchases a new license.', 'commission-on-new-license-purchase', $slug ), $commission ) ) ?></li>- <?php if ( is_object( $affiliate_terms ) && $affiliate_terms->has_renewals_commission() ) : ?>- <li><?php echo esc_html( sprintf( fs_text_inline( 'Get commission for automated subscription renewals.', 'renewals-commission', $slug ) ) ) ?></li>- <?php endif ?>- <?php if ( is_object( $affiliate_terms ) && ( ! $affiliate_terms->is_session_cookie() ) ) : ?>- <li><?php echo esc_html( sprintf( fs_text_inline( '%s tracking cookie after the first visit to maximize earnings potential.', 'affiliate-tracking', $slug ), $affiliate_tracking ) ) ?></li>- <?php endif ?>- <?php if ( is_object( $affiliate_terms ) && $affiliate_terms->has_lifetime_commission() ) : ?>- <li><?php fs_esc_html_echo_inline( 'Unlimited commissions.', 'unlimited-commissions', $slug ) ?></li>- <?php endif ?>- <li><?php echo esc_html( sprintf( fs_text_inline( '%s minimum payout amount.', 'minimum-payout-amount', $slug ), '$100' ) ) ?></li>- <li><?php fs_esc_html_echo_inline( 'Payouts are in USD and processed monthly via PayPal.', 'payouts-unit-and-processing', $slug ) ?></li>- <li><?php fs_esc_html_echo_inline( 'As we reserve 30 days for potential refunds, we only pay commissions that are older than 30 days.', 'commission-payment', $slug ) ?></li>- </ul>- <div id="application_form_container" <?php echo ( $is_pending_affiliate ) ? '' : 'style="display: none"' ?>>- <h3><?php fs_esc_html_echo_inline( 'Affiliate', 'affiliate', $slug ) ?></h3>- <form>- <div class="input-container input-container-text">- <label class="input-label"><?php fs_esc_html_echo_inline( 'Email address', 'email-address', $slug ) ?></label>- <input id="email_address" type="text" value="<?php echo esc_attr( $email_address ) ?>" class="regular-text" <?php echo ( $readonly || is_object( $user ) ) ? 'readonly' : '' ?>>- </div>- <div class="input-container input-container-text">- <label class="input-label"><?php fs_esc_html_echo_inline( 'Full name', 'full-name', $slug ) ?></label>- <input id="full_name" type="text" value="<?php echo esc_attr( $full_name ) ?>" class="regular-text" <?php echo $readonly ?>>- </div>- <div class="input-container input-container-text">- <label class="input-label"><?php fs_esc_html_echo_inline( 'PayPal account email address', 'paypal-account-email-address', $slug ) ?></label>- <input id="paypal_email" type="text" value="<?php echo esc_attr( $paypal_email_address ) ?>" class="regular-text" <?php echo $readonly ?>>- </div>- <div class="input-container input-container-text">- <label class="input-label"><?php echo esc_html( sprintf( fs_text_inline( 'Where are you going to promote the %s?', 'domain-field-label', $slug ), $module_type ) ) ?></label>- <input id="domain" type="text" value="<?php echo esc_attr( $domain ) ?>" class="domain regular-text" <?php echo $readonly ?>>- <p class="description"><?php echo esc_html( sprintf( fs_text_inline( 'Enter the domain of your website or other websites from where you plan to promote the %s.', 'domain-field-desc', $slug ), $module_type ) ) ?></p>- <?php if ( ! $is_affiliate ) : ?>- <a id="add_domain" href="#" class="disabled">+ <?php fs_esc_html_echo_inline( 'Add another domain', 'add-another-domain', $slug ) ?>...</a>- <?php endif ?>- </div>- <div id="extra_domains_container" class="input-container input-container-text" <?php echo $is_pending_affiliate ? '' : 'style="display: none"' ?>>- <label class="input-label"><?php fs_esc_html_echo_inline( 'Extra Domains', 'extra-domain-fields-label', $slug ) ?></label>- <p class="description"><?php fs_esc_html_echo_inline( 'Extra domains where you will be marketing the product from.', 'extra-domain-fields-desc', $slug ) ?></p>- <?php if ( $is_pending_affiliate && ! empty( $extra_domains ) ) : ?>- <?php foreach ( $extra_domains as $extra_domain ) : ?>- <div class="extra-domain-input-container">- <input type="text" value="<?php echo esc_attr( $extra_domain ) ?>" class="domain regular-text" <?php echo $readonly ?>>- </div>- <?php endforeach ?>- <?php endif ?>- </div>- <div class="input-container">- <label class="input-label"><?php fs_esc_html_echo_inline( 'Promotion methods', 'promotion-methods', $slug ) ?></label>- <div>- <input id="promotion_method_social_media" type="checkbox" <?php checked( $promotion_method_social_media ) ?> <?php disabled( $is_affiliate ) ?>/>- <label for="promotion_method_social_media"><?php fs_esc_html_echo_inline( 'Social media (Facebook, Twitter, etc.)', 'social-media', $slug ) ?></label>- </div>- <div>- <input id="promotion_method_mobile_apps" type="checkbox" <?php checked( $promotion_method_mobile_apps ) ?> <?php disabled( $is_affiliate ) ?>/>- <label for="promotion_method_mobile_apps"><?php fs_esc_html_echo_inline( 'Mobile apps', 'mobile-apps', $slug ) ?></label>- </div>- </div>- <div class="input-container input-container-text">- <label class="input-label"><nobr><?php fs_esc_html_echo_inline( 'Website, email, and social media statistics (optional)', 'statistics-information-field-label', $slug ) ?></nobr></label>- <textarea id="statistics_information" rows="5" <?php echo $readonly ?> class="regular-text"><?php echo $statistics_information ?></textarea>- <?php if ( ! $is_affiliate ) : ?>- <p class="description"><?php fs_esc_html_echo_inline( 'Please feel free to provide any relevant website or social media statistics, e.g. monthly unique site visits, number of email subscribers, followers, etc. (we will keep this information confidential).', 'statistics-information-field-desc', $slug ) ?></p>- <?php endif ?>- </div>- <div class="input-container input-container-text">- <label class="input-label"><?php fs_esc_html_echo_inline( 'How will you promote us?', 'promotion-method-desc-field-label', $slug ) ?></label>- <textarea id="promotion_method_description" rows="5" <?php echo $readonly ?> class="regular-text"><?php echo $promotion_method_description ?></textarea>- <?php if ( ! $is_affiliate ) : ?>- <p class="description"><?php echo esc_html( sprintf( fs_text_inline( 'Please provide details on how you intend to promote %s (please be as specific as possible).', 'promotion-method-desc-field-desc', $slug ), $plugin_title ) ) ?></p>- <?php endif ?>- </div>- <?php if ( ! $is_affiliate ) : ?>- <div>- <input type="checkbox" id="legal_consent_checkbox">- <label for="legal_consent_checkbox">I agree to the <a href="<?php echo $affiliate_program_terms_url ?>" target="_blank" rel="noopener">Referrer Program</a>'s terms & conditions.</label>- </div>- <?php endif ?>- </form>- </div>- <?php if ( ! $is_affiliate ) : ?>- <a id="cancel_button" href="#" class="button button-secondary button-cancel" style="display: none"><?php fs_esc_html_echo_inline( 'Cancel', 'cancel', $slug ) ?></a>- <a id="submit_button" class="button button-primary disabled" href="#" style="display: none"><?php echo esc_html( $apply_to_become_affiliate_text ) ?></a>- <a id="apply_button" class="button button-primary" href="#"><?php fs_esc_html_echo_inline( 'Become an affiliate', 'become-an-affiliate', $slug ) ?></a>- <?php endif ?>- </div>- </div>- </div>- </div>- </form>- <script type="text/javascript">- jQuery(function ($) {- var- $contentWrapper = $('#fs_affiliation_content_wrapper'),- $socialMedia = $('#promotion_method_social_media'),- $mobileApps = $('#promotion_method_mobile_apps'),- $applyButton = $('#apply_button'),- $submitButton = $('#submit_button'),- $cancelButton = $('#cancel_button'),- $applicationFormContainer = $('#application_form_container'),- $errorMessageContainer = $('#error_message'),- $domain = $('#domain'),- $addDomain = $('#add_domain'),- $extraDomainsContainer = $('#extra_domains_container'),- $legalConsentCheckbox = $( '#legal_consent_checkbox' );-- $applyButton.click(function (evt) {- evt.preventDefault();-- var $this = $(this);- $this.hide();-- $applicationFormContainer.show();- $cancelButton.show();- $submitButton.show();-- $contentWrapper.find('input[type="text"]:first').focus();- });-- $submitButton.click(function (evt) {- evt.preventDefault();-- var $this = $(this);-- if ($this.hasClass('disabled')) {- return;- }-- $errorMessageContainer.hide();-- var- $emailAddress = $('#email_address'),- emailAddress = null,- paypalEmailAddress = $('#paypal_email').val().trim();-- if (1 === $emailAddress.length) {- emailAddress = $emailAddress.val().trim();-- if (0 === emailAddress.length) {- showErrorMessage('<?php fs_esc_js_echo_inline( 'Email address is required.', 'email-address-is-required', $slug ) ?>');- return;- }- }-- if (0 === paypalEmailAddress.length) {- showErrorMessage('<?php fs_esc_js_echo_inline( 'PayPal email address is required.', 'paypal-email-address-is-required', $slug ) ?>');- return;- }-- var- $extraDomains = $extraDomainsContainer.find('.domain'),- domain = $domain.val().trim().toLowerCase(),- extraDomains = [];-- if (0 === domain.length) {- showErrorMessage('<?php fs_esc_js_echo_inline( 'Domain is required.', 'domain-is-required', $slug ) ?>');- return;- } else if ('freemius.com' === domain) {- showErrorMessage('<?php fs_esc_js_echo_inline( 'Invalid domain', 'invalid-domain', $slug ) ?>' + ' [' + domain + '].');- return;- }-- if ($extraDomains.length > 0) {- var hasError = false;-- $extraDomains.each(function () {- var- $this = $(this),- extraDomain = $this.val().trim().toLowerCase();- if (0 === extraDomain.length || extraDomain === domain) {- return true;- } else if ('freemius.com' === extraDomain) {- showErrorMessage('<?php fs_esc_js_echo_inline( 'Invalid domain', 'invalid-domain', $slug ) ?>' + ' [' + extraDomain + '].');- hasError = true;- return false;- }-- extraDomains.push(extraDomain);- });-- if (hasError) {- return;- }- }-- var- promotionMethods = [],- statisticsInformation = $('#statistics_information').val(),- promotionMethodDescription = $('#promotion_method_description').val();-- if ($socialMedia.attr('checked')) {- promotionMethods.push('social_media');- }-- if ($mobileApps.attr('checked')) {- promotionMethods.push('mobile_apps');- }-- var affiliate = {- full_name : $('#full_name').val().trim(),- paypal_email : paypalEmailAddress,- stats_description : statisticsInformation,- promotion_method_description: promotionMethodDescription- };-- if (null !== emailAddress) {- affiliate.email = emailAddress;- }-- affiliate.domain = domain;- affiliate.additional_domains = extraDomains;-- if (promotionMethods.length > 0) {- affiliate.promotion_methods = promotionMethods.join(',');- }-- $.ajax({- url : <?php echo Freemius::ajax_url() ?>,- method : 'POST',- data : {- action : '<?php echo $fs->get_ajax_action( 'submit_affiliate_application' ) ?>',- security : '<?php echo $fs->get_ajax_security( 'submit_affiliate_application' ) ?>',- module_id: '<?php echo $module_id ?>',- affiliate: affiliate- },- beforeSend: function () {- $cancelButton.addClass('disabled');- $submitButton.addClass('disabled');- $submitButton.text('<?php fs_esc_js_echo_inline( 'Submitting', 'submitting' ) ?>...');- },- success : function (result) {- if (result.success) {- location.reload();- } else {- if (result.error && result.error.length > 0) {- showErrorMessage(result.error);- }-- $cancelButton.removeClass('disabled');- $submitButton.removeClass('disabled');- $submitButton.text('<?php echo esc_js( $apply_to_become_affiliate_text ) ?>')- }- }- });- });-- $cancelButton.click(function (evt) {- evt.preventDefault();-- var $this = $(this);-- if ($this.hasClass('disabled')) {- return;- }-- $applicationFormContainer.hide();- $this.hide();- $submitButton.hide();-- $applyButton.show();-- window.scrollTo(0, 0);- });-- $domain.on('input propertychange', onDomainChange);-- $addDomain.click(function (evt) {- evt.preventDefault();-- var- $this = $(this),- domain = $domain.val().trim();-- if ($this.hasClass('disabled') || 0 === domain.length) {- return;- }-- $domain.off('input propertychange');- $this.addClass('disabled');-- var- $extraDomainInputContainer = $('<div class="extra-domain-input-container"><input type="text" class="domain regular-text"/></div>'),- $extraDomainInput = $extraDomainInputContainer.find('input'),- $removeDomain = $('<a href="#" class="remove-domain"><i class="dashicons dashicons-no" title="<?php fs_esc_js_echo_inline( 'Remove', 'remove', $slug ) ?>"></i></a>');-- $extraDomainInputContainer.append($removeDomain);-- $extraDomainInput.on('input propertychange', onDomainChange);-- $removeDomain.click(function (evt) {- evt.preventDefault();-- var- $extraDomainInputs = $('.extra-domain-input-container .domain');-- if (1 === $extraDomainInputs.length)- $extraDomainInputs.val('').focus();- else- $(this).parent().remove();- });-- $extraDomainsContainer.show();-- $extraDomainInputContainer.appendTo($extraDomainsContainer);- $extraDomainInput.focus();-- $this.appendTo($extraDomainsContainer);- });-- /**- * @author Leo Fajardo (@leorw)- */- function onDomainChange() {- var- domain = $(this).val().trim();-- if (domain.length > 0) {- $addDomain.removeClass('disabled');- } else {- $addDomain.addClass('disabled');- }- }-- /**- * @author Leo Fajardo (@leorw)- *- * @param {String} message- */- function showErrorMessage(message) {- $errorMessageContainer.find('strong').text(message);- $errorMessageContainer.show();-- window.scrollTo(0, 0);- }-- /**- * @author Xiaheng Chen (@xhchen)- *- * @since 2.4.0- */- $legalConsentCheckbox.click( function () {- if ( $( this ).prop( 'checked' ) ) {- $submitButton.removeClass( 'disabled' );- } else {- $submitButton.addClass( 'disabled' );- }- } );- });- </script>- </div>-<?php- if ( $has_tabs ) {- $fs->_add_tabs_after_content();- }-- $params = array(- 'page' => 'affiliation',- 'module_id' => $module_id,- 'module_slug' => $slug,- 'module_version' => $fs->get_plugin_version(),- );- fs_require_template( 'powered-by.php', $params );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.3 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + * @var string $plugin_title + */ + $fs = freemius( $VARS['id'] ); + $plugin_title = $VARS['plugin_title']; + + $slug = $fs->get_slug(); + + $user = $fs->get_user(); + $affiliate = $fs->get_affiliate(); + $affiliate_terms = $fs->get_affiliate_terms(); + + $module_type = $fs->is_plugin() ? + WP_FS__MODULE_TYPE_PLUGIN : + WP_FS__MODULE_TYPE_THEME; + + $commission = $affiliate_terms->get_formatted_commission(); + + $readonly = false; + $is_affiliate = is_object( $affiliate ); + $is_pending_affiliate = false; + $email_address = ( is_object( $user ) ? + $user->email : + '' ); + $full_name = ( is_object( $user ) ? + $user->get_name() : + '' ); + $paypal_email_address = ''; + $domain = ''; + $extra_domains = array(); + $promotion_method_social_media = false; + $promotion_method_mobile_apps = false; + $statistics_information = false; + $promotion_method_description = false; + $members_dashboard_login_url = 'https://users.freemius.com/login'; + + $affiliate_application_data = $fs->get_affiliate_application_data(); + + if ( $is_affiliate && $affiliate->is_pending() ) { + $readonly = 'readonly'; + $is_pending_affiliate = true; + + $paypal_email_address = $affiliate->paypal_email; + $domain = $affiliate->domain; + $statistics_information = $affiliate_application_data['stats_description']; + $promotion_method_description = $affiliate_application_data['promotion_method_description']; + + if ( ! empty( $affiliate_application_data['additional_domains'] ) ) { + $extra_domains = $affiliate_application_data['additional_domains']; + } + + if ( ! empty( $affiliate_application_data['promotion_methods'] ) ) { + $promotion_methods = explode( ',', $affiliate_application_data['promotion_methods'] ); + $promotion_method_social_media = in_array( 'social_media', $promotion_methods ); + $promotion_method_mobile_apps = in_array( 'mobile_apps', $promotion_methods ); + } + } else { + if ( ! is_object( $user ) ) { + $current_user = Freemius::_get_current_wp_user(); + $full_name = trim( $current_user->user_firstname . ' ' . $current_user->user_lastname ); + $email_address = $current_user->user_email; + } + + $domain = Freemius::get_unfiltered_site_url( null, true ); + } + + $affiliate_tracking = 30; + + if ( is_object( $affiliate_terms ) ) { + $affiliate_tracking = ( ! is_null( $affiliate_terms->cookie_days ) ? + ( $affiliate_terms->cookie_days . '-day' ) : + fs_text_inline( 'Non-expiring', 'non-expiring', $slug ) ); + } + + $apply_to_become_affiliate_text = fs_text_inline( 'Apply to become an affiliate', 'apply-to-become-an-affiliate', $slug ); + + $module_id = $fs->get_id(); + $affiliate_program_terms_url = "https://freemius.com/plugin/{$module_id}/{$slug}/legal/affiliate-program/"; + + $has_tabs = $fs->_add_tabs_before_content(); +?> +<div id="fs_affiliation_content_wrapper" class="wrap"> + <form method="post" action=""> + <div id="poststuff"> + <div class="postbox"> + <div class="inside"> + <div id="messages"> + <div id="error_message" class="error" style="display: none"> + <p><strong></strong></p> + </div> + <div id="message" class="updated" style="display: none"> + <p><strong></strong></p> + </div> + <?php if ( $is_affiliate ) : ?> + <?php if ( $affiliate->is_active() ) : ?> + <div class="updated"> + <p><strong><?php + echo sprintf( + fs_esc_html_inline( "Your affiliate application for %s has been accepted! Log in to your affiliate area at: %s.", 'affiliate-application-accepted', $slug ), + $plugin_title, + sprintf( + '<a href="%s" target="_blank" rel="noopener">%s</a>', + $members_dashboard_login_url, + $members_dashboard_login_url + ) + ); + ?></strong></p> + </div> + <?php else : ?> + <?php + $message_text = ''; + + if ( $is_pending_affiliate ) { + $message_text = fs_text_inline( "Thank you for applying for our affiliate program, we'll review your details during the next 14 days and will get back to you with further information.", 'affiliate-application-thank-you', $slug ); + $message_container_class = 'updated'; + } else if ( $affiliate->is_suspended() ) { + $message_text = fs_text_inline( 'Your affiliation account was temporarily suspended.', 'affiliate-account-suspended', $slug ); + $message_container_class = 'notice notice-warning'; + } else if ( $affiliate->is_rejected() ) { + $message_text = fs_text_inline( "Thank you for applying for our affiliate program, unfortunately, we've decided at this point to reject your application. Please try again in 30 days.", 'affiliate-application-rejected', $slug ); + $message_container_class = 'error'; + } else if ( $affiliate->is_blocked() ) { + $message_text = fs_text_inline( 'Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support.', 'affiliate-account-blocked', $slug ); + $message_container_class = 'error'; + } + ?> + <div class="<?php echo $message_container_class ?>"> + <p><strong><?php echo esc_html( $message_text ) ?></strong></p> + </div> + <?php endif ?> + <?php endif ?> + </div> + <div class="entry-content"> + <?php if ( ! $is_affiliate ) : ?> + <div id="application_messages_container"> + <p><?php echo esc_html( sprintf( fs_text_inline( 'Like the %s? Become our ambassador and earn cash ;-)', 'become-an-ambassador', $slug ), $module_type ) ) ?></p> + <p><?php echo esc_html( sprintf( fs_text_inline( 'Refer new customers to our %s and earn %s commission on each successful sale you refer!', 'refer-new-customers', $slug ), $module_type, $commission ) ) ?></p> + </div> + <?php endif ?> + <h3><?php fs_esc_html_echo_inline( 'Program Summary', 'program-summary', $slug ) ?></h3> + <ul> + <li><?php echo esc_html( sprintf( fs_text_inline( '%s commission when a customer purchases a new license.', 'commission-on-new-license-purchase', $slug ), $commission ) ) ?></li> + <?php if ( is_object( $affiliate_terms ) && $affiliate_terms->has_renewals_commission() ) : ?> + <li><?php echo esc_html( sprintf( fs_text_inline( 'Get commission for automated subscription renewals.', 'renewals-commission', $slug ) ) ) ?></li> + <?php endif ?> + <?php if ( is_object( $affiliate_terms ) && ( ! $affiliate_terms->is_session_cookie() ) ) : ?> + <li><?php echo esc_html( sprintf( fs_text_inline( '%s tracking cookie after the first visit to maximize earnings potential.', 'affiliate-tracking', $slug ), $affiliate_tracking ) ) ?></li> + <?php endif ?> + <?php if ( is_object( $affiliate_terms ) && $affiliate_terms->has_lifetime_commission() ) : ?> + <li><?php fs_esc_html_echo_inline( 'Unlimited commissions.', 'unlimited-commissions', $slug ) ?></li> + <?php endif ?> + <li><?php echo esc_html( sprintf( fs_text_inline( '%s minimum payout amount.', 'minimum-payout-amount', $slug ), '$100' ) ) ?></li> + <li><?php fs_esc_html_echo_inline( 'Payouts are in USD and processed monthly via PayPal.', 'payouts-unit-and-processing', $slug ) ?></li> + <li><?php fs_esc_html_echo_inline( 'As we reserve 30 days for potential refunds, we only pay commissions that are older than 30 days.', 'commission-payment', $slug ) ?></li> + </ul> + <div id="application_form_container" <?php echo ( $is_pending_affiliate ) ? '' : 'style="display: none"' ?>> + <h3><?php fs_esc_html_echo_inline( 'Affiliate', 'affiliate', $slug ) ?></h3> + <form> + <div class="input-container input-container-text"> + <label class="input-label"><?php fs_esc_html_echo_inline( 'Email address', 'email-address', $slug ) ?></label> + <input id="email_address" type="text" value="<?php echo esc_attr( $email_address ) ?>" class="regular-text" <?php echo ( $readonly || is_object( $user ) ) ? 'readonly' : '' ?>> + </div> + <div class="input-container input-container-text"> + <label class="input-label"><?php fs_esc_html_echo_inline( 'Full name', 'full-name', $slug ) ?></label> + <input id="full_name" type="text" value="<?php echo esc_attr( $full_name ) ?>" class="regular-text" <?php echo $readonly ?>> + </div> + <div class="input-container input-container-text"> + <label class="input-label"><?php fs_esc_html_echo_inline( 'PayPal account email address', 'paypal-account-email-address', $slug ) ?></label> + <input id="paypal_email" type="text" value="<?php echo esc_attr( $paypal_email_address ) ?>" class="regular-text" <?php echo $readonly ?>> + </div> + <div class="input-container input-container-text"> + <label class="input-label"><?php echo esc_html( sprintf( fs_text_inline( 'Where are you going to promote the %s?', 'domain-field-label', $slug ), $module_type ) ) ?></label> + <input id="domain" type="text" value="<?php echo esc_attr( $domain ) ?>" class="domain regular-text" <?php echo $readonly ?>> + <p class="description"><?php echo esc_html( sprintf( fs_text_inline( 'Enter the domain of your website or other websites from where you plan to promote the %s.', 'domain-field-desc', $slug ), $module_type ) ) ?></p> + <?php if ( ! $is_affiliate ) : ?> + <a id="add_domain" href="#" class="disabled">+ <?php fs_esc_html_echo_inline( 'Add another domain', 'add-another-domain', $slug ) ?>...</a> + <?php endif ?> + </div> + <div id="extra_domains_container" class="input-container input-container-text" <?php echo $is_pending_affiliate ? '' : 'style="display: none"' ?>> + <label class="input-label"><?php fs_esc_html_echo_inline( 'Extra Domains', 'extra-domain-fields-label', $slug ) ?></label> + <p class="description"><?php fs_esc_html_echo_inline( 'Extra domains where you will be marketing the product from.', 'extra-domain-fields-desc', $slug ) ?></p> + <?php if ( $is_pending_affiliate && ! empty( $extra_domains ) ) : ?> + <?php foreach ( $extra_domains as $extra_domain ) : ?> + <div class="extra-domain-input-container"> + <input type="text" value="<?php echo esc_attr( $extra_domain ) ?>" class="domain regular-text" <?php echo $readonly ?>> + </div> + <?php endforeach ?> + <?php endif ?> + </div> + <div class="input-container"> + <label class="input-label"><?php fs_esc_html_echo_inline( 'Promotion methods', 'promotion-methods', $slug ) ?></label> + <div> + <input id="promotion_method_social_media" type="checkbox" <?php checked( $promotion_method_social_media ) ?> <?php disabled( $is_affiliate ) ?>/> + <label for="promotion_method_social_media"><?php fs_esc_html_echo_inline( 'Social media (Facebook, Twitter, etc.)', 'social-media', $slug ) ?></label> + </div> + <div> + <input id="promotion_method_mobile_apps" type="checkbox" <?php checked( $promotion_method_mobile_apps ) ?> <?php disabled( $is_affiliate ) ?>/> + <label for="promotion_method_mobile_apps"><?php fs_esc_html_echo_inline( 'Mobile apps', 'mobile-apps', $slug ) ?></label> + </div> + </div> + <div class="input-container input-container-text"> + <label class="input-label"><nobr><?php fs_esc_html_echo_inline( 'Website, email, and social media statistics (optional)', 'statistics-information-field-label', $slug ) ?></nobr></label> + <textarea id="statistics_information" rows="5" <?php echo $readonly ?> class="regular-text"><?php echo $statistics_information ?></textarea> + <?php if ( ! $is_affiliate ) : ?> + <p class="description"><?php fs_esc_html_echo_inline( 'Please feel free to provide any relevant website or social media statistics, e.g. monthly unique site visits, number of email subscribers, followers, etc. (we will keep this information confidential).', 'statistics-information-field-desc', $slug ) ?></p> + <?php endif ?> + </div> + <div class="input-container input-container-text"> + <label class="input-label"><?php fs_esc_html_echo_inline( 'How will you promote us?', 'promotion-method-desc-field-label', $slug ) ?></label> + <textarea id="promotion_method_description" rows="5" <?php echo $readonly ?> class="regular-text"><?php echo $promotion_method_description ?></textarea> + <?php if ( ! $is_affiliate ) : ?> + <p class="description"><?php echo esc_html( sprintf( fs_text_inline( 'Please provide details on how you intend to promote %s (please be as specific as possible).', 'promotion-method-desc-field-desc', $slug ), $plugin_title ) ) ?></p> + <?php endif ?> + </div> + <?php if ( ! $is_affiliate ) : ?> + <div> + <input type="checkbox" id="legal_consent_checkbox"> + <label for="legal_consent_checkbox">I agree to the <a href="<?php echo $affiliate_program_terms_url ?>" target="_blank" rel="noopener">Referrer Program</a>'s terms & conditions.</label> + </div> + <?php endif ?> + </form> + </div> + <?php if ( ! $is_affiliate ) : ?> + <a id="cancel_button" href="#" class="button button-secondary button-cancel" style="display: none"><?php fs_esc_html_echo_inline( 'Cancel', 'cancel', $slug ) ?></a> + <a id="submit_button" class="button button-primary disabled" href="#" style="display: none"><?php echo esc_html( $apply_to_become_affiliate_text ) ?></a> + <a id="apply_button" class="button button-primary" href="#"><?php fs_esc_html_echo_inline( 'Become an affiliate', 'become-an-affiliate', $slug ) ?></a> + <?php endif ?> + </div> + </div> + </div> + </div> + </form> + <script type="text/javascript"> + jQuery(function ($) { + var + $contentWrapper = $('#fs_affiliation_content_wrapper'), + $socialMedia = $('#promotion_method_social_media'), + $mobileApps = $('#promotion_method_mobile_apps'), + $applyButton = $('#apply_button'), + $submitButton = $('#submit_button'), + $cancelButton = $('#cancel_button'), + $applicationFormContainer = $('#application_form_container'), + $errorMessageContainer = $('#error_message'), + $domain = $('#domain'), + $addDomain = $('#add_domain'), + $extraDomainsContainer = $('#extra_domains_container'), + $legalConsentCheckbox = $( '#legal_consent_checkbox' ); + + $applyButton.click(function (evt) { + evt.preventDefault(); + + var $this = $(this); + $this.hide(); + + $applicationFormContainer.show(); + $cancelButton.show(); + $submitButton.show(); + + $contentWrapper.find('input[type="text"]:first').focus(); + }); + + $submitButton.click(function (evt) { + evt.preventDefault(); + + var $this = $(this); + + if ($this.hasClass('disabled')) { + return; + } + + $errorMessageContainer.hide(); + + var + $emailAddress = $('#email_address'), + emailAddress = null, + paypalEmailAddress = $('#paypal_email').val().trim(); + + if (1 === $emailAddress.length) { + emailAddress = $emailAddress.val().trim(); + + if (0 === emailAddress.length) { + showErrorMessage('<?php fs_esc_js_echo_inline( 'Email address is required.', 'email-address-is-required', $slug ) ?>'); + return; + } + } + + if (0 === paypalEmailAddress.length) { + showErrorMessage('<?php fs_esc_js_echo_inline( 'PayPal email address is required.', 'paypal-email-address-is-required', $slug ) ?>'); + return; + } + + var + $extraDomains = $extraDomainsContainer.find('.domain'), + domain = $domain.val().trim().toLowerCase(), + extraDomains = []; + + if (0 === domain.length) { + showErrorMessage('<?php fs_esc_js_echo_inline( 'Domain is required.', 'domain-is-required', $slug ) ?>'); + return; + } else if ('freemius.com' === domain) { + showErrorMessage('<?php fs_esc_js_echo_inline( 'Invalid domain', 'invalid-domain', $slug ) ?>' + ' [' + domain + '].'); + return; + } + + if ($extraDomains.length > 0) { + var hasError = false; + + $extraDomains.each(function () { + var + $this = $(this), + extraDomain = $this.val().trim().toLowerCase(); + if (0 === extraDomain.length || extraDomain === domain) { + return true; + } else if ('freemius.com' === extraDomain) { + showErrorMessage('<?php fs_esc_js_echo_inline( 'Invalid domain', 'invalid-domain', $slug ) ?>' + ' [' + extraDomain + '].'); + hasError = true; + return false; + } + + extraDomains.push(extraDomain); + }); + + if (hasError) { + return; + } + } + + var + promotionMethods = [], + statisticsInformation = $('#statistics_information').val(), + promotionMethodDescription = $('#promotion_method_description').val(); + + if ($socialMedia.attr('checked')) { + promotionMethods.push('social_media'); + } + + if ($mobileApps.attr('checked')) { + promotionMethods.push('mobile_apps'); + } + + var affiliate = { + full_name : $('#full_name').val().trim(), + paypal_email : paypalEmailAddress, + stats_description : statisticsInformation, + promotion_method_description: promotionMethodDescription + }; + + if (null !== emailAddress) { + affiliate.email = emailAddress; + } + + affiliate.domain = domain; + affiliate.additional_domains = extraDomains; + + if (promotionMethods.length > 0) { + affiliate.promotion_methods = promotionMethods.join(','); + } + + $.ajax({ + url : <?php echo Freemius::ajax_url() ?>, + method : 'POST', + data : { + action : '<?php echo $fs->get_ajax_action( 'submit_affiliate_application' ) ?>', + security : '<?php echo $fs->get_ajax_security( 'submit_affiliate_application' ) ?>', + module_id: '<?php echo $module_id ?>', + affiliate: affiliate + }, + beforeSend: function () { + $cancelButton.addClass('disabled'); + $submitButton.addClass('disabled'); + $submitButton.text('<?php fs_esc_js_echo_inline( 'Submitting', 'submitting' ) ?>...'); + }, + success : function (result) { + if (result.success) { + location.reload(); + } else { + if (result.error && result.error.length > 0) { + showErrorMessage(result.error); + } + + $cancelButton.removeClass('disabled'); + $submitButton.removeClass('disabled'); + $submitButton.text('<?php echo esc_js( $apply_to_become_affiliate_text ) ?>') + } + } + }); + }); + + $cancelButton.click(function (evt) { + evt.preventDefault(); + + var $this = $(this); + + if ($this.hasClass('disabled')) { + return; + } + + $applicationFormContainer.hide(); + $this.hide(); + $submitButton.hide(); + + $applyButton.show(); + + window.scrollTo(0, 0); + }); + + $domain.on('input propertychange', onDomainChange); + + $addDomain.click(function (evt) { + evt.preventDefault(); + + var + $this = $(this), + domain = $domain.val().trim(); + + if ($this.hasClass('disabled') || 0 === domain.length) { + return; + } + + $domain.off('input propertychange'); + $this.addClass('disabled'); + + var + $extraDomainInputContainer = $('<div class="extra-domain-input-container"><input type="text" class="domain regular-text"/></div>'), + $extraDomainInput = $extraDomainInputContainer.find('input'), + $removeDomain = $('<a href="#" class="remove-domain"><i class="dashicons dashicons-no" title="<?php fs_esc_js_echo_inline( 'Remove', 'remove', $slug ) ?>"></i></a>'); + + $extraDomainInputContainer.append($removeDomain); + + $extraDomainInput.on('input propertychange', onDomainChange); + + $removeDomain.click(function (evt) { + evt.preventDefault(); + + var + $extraDomainInputs = $('.extra-domain-input-container .domain'); + + if (1 === $extraDomainInputs.length) + $extraDomainInputs.val('').focus(); + else + $(this).parent().remove(); + }); + + $extraDomainsContainer.show(); + + $extraDomainInputContainer.appendTo($extraDomainsContainer); + $extraDomainInput.focus(); + + $this.appendTo($extraDomainsContainer); + }); + + /** + * @author Leo Fajardo (@leorw) + */ + function onDomainChange() { + var + domain = $(this).val().trim(); + + if (domain.length > 0) { + $addDomain.removeClass('disabled'); + } else { + $addDomain.addClass('disabled'); + } + } +
I'll analyze this diff for security vulnerabilities. **Analysis Result:** Vulnerability Existed: no This diff shows a line-ending change only (LF vs CRLF or similar whitespace normalization). The actual code content remains identical between versions 1.2.11 and 1.2.12. **Key Observations:** 1. **No functional changes**: All PHP logic, JavaScript code, and output escaping remain the same 2. **Existing security measures are preserved**: - `esc_html()` is used for HTML context escaping - `esc_attr()` is used for attribute context escaping - `esc_js()` is used for JavaScript context escaping - `fs_esc_html_inline()`, `fs_esc_js_echo_inline()` custom escaping functions are maintained - WordPress nonce verification via `$fs->get_ajax_security()` is present 3. **No new vulnerabilities introduced**: The escaping patterns that were in place remain intact **Conclusion:** This is a formatting/whitespace-only update with no security implications. The code maintains proper output escaping throughout and contains no detectable security vulnerabilities in either version.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/deactivation/contact.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/deactivation/contact.php 2026-01-19 00:17:37.675046521 +0000@@ -1,23 +1,23 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- */- $fs = freemius( $VARS['id'] );- $slug = $fs->get_slug();-- echo fs_text_inline( 'Sorry for the inconvenience and we are here to help if you give us a chance.', 'contact-support-before-deactivation', $slug )- . sprintf(" <a href='%s' class='button button-small button-primary'>%s</a>",- $fs->contact_url( 'technical_support' ),- fs_text_inline( 'Contact Support', 'contact-support', $slug )- );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + */ + $fs = freemius( $VARS['id'] ); + $slug = $fs->get_slug(); + + echo fs_text_inline( 'Sorry for the inconvenience and we are here to help if you give us a chance.', 'contact-support-before-deactivation', $slug ) + . sprintf(" <a href='%s' class='button button-small button-primary'>%s</a>", + $fs->contact_url( 'technical_support' ), + fs_text_inline( 'Contact Support', 'contact-support', $slug ) + );
# Security Analysis - Code Diff Review Vulnerability Existed: no **Explanation:** The diff shows only formatting changes (line ending normalization from CRLF to LF). The actual code content remains identical between versions 1.2.11 and 1.2.12. No security fixes or vulnerability remediation occurred in this change. The code itself uses appropriate security practices: - `esc_attr()` equivalent protection is implied through `sprintf()` with the URL from `$fs->contact_url()` (a Freemius library method that should handle escaping) - `fs_text_inline()` appears to be a localization wrapper that should handle output escaping - No new vulnerabilities were introduced, and no existing vulnerabilities were fixed **Note:** This is purely a whitespace/line-ending normalization commit with no functional code changes.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/deactivation/index.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/deactivation/index.php 2026-01-19 00:17:37.675046521 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Security Vulnerability - Whitespace/Formatting Change - inc/freemius/templates/forms/deactivation/index.php [1-3] Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace and formatting changes (likely line ending normalization or tab/space consistency adjustments). There are no functional code changes, no security vulnerability fixes, and no introduction of new vulnerabilities. The file remains a simple PHP file with only comments, designed to prevent direct file access and hide directory structure. No security-related modifications are present in this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/deactivation/retry-skip.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/deactivation/retry-skip.php 2026-01-19 00:17:37.675046521 +0000@@ -1,24 +1,24 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- */- $fs = freemius( $VARS['id'] );- $slug = $fs->get_slug();-- $skip_url = fs_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $fs->get_unique_affix() . '_skip_activation' ) ), $fs->get_unique_affix() . '_skip_activation' );- $skip_text = strtolower( fs_text_x_inline( 'Skip', 'verb', 'skip', $slug ) );- $use_plugin_anonymously_text = fs_text_inline( 'Click here to use the plugin anonymously', 'click-here-to-use-plugin-anonymously', $slug );-- echo sprintf( fs_text_inline( "You might have missed it, but you don't have to share any data and can just %s the opt-in.", 'dont-have-to-share-any-data', $slug ), "<a href='{$skip_url}'>{$skip_text}</a>" )+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + */ + $fs = freemius( $VARS['id'] ); + $slug = $fs->get_slug(); + + $skip_url = fs_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $fs->get_unique_affix() . '_skip_activation' ) ), $fs->get_unique_affix() . '_skip_activation' ); + $skip_text = strtolower( fs_text_x_inline( 'Skip', 'verb', 'skip', $slug ) ); + $use_plugin_anonymously_text = fs_text_inline( 'Click here to use the plugin anonymously', 'click-here-to-use-plugin-anonymously', $slug ); + + echo sprintf( fs_text_inline( "You might have missed it, but you don't have to share any data and can just %s the opt-in.", 'dont-have-to-share-any-data', $slug ), "<a href='{$skip_url}'>{$skip_text}</a>" ) . " <a href='{$skip_url}' class='button button-small button-secondary'>{$use_plugin_anonymously_text}</a>";\ No newline at end of file
Vulnerability Existed: no
No CWE identified - File: inc/freemius/templates/forms/deactivation/retry-skip.php
Old Code:
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* @var array $VARS
*/
$fs = freemius( $VARS['id'] );
$slug = $fs->get_slug();
$skip_url = fs_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $fs->get_unique_affix() . '_skip_activation' ) ), $fs->get_unique_affix() . '_skip_activation' );
$skip_text = strtolower( fs_text_x_inline( 'Skip', 'verb', 'skip', $slug ) );
$use_plugin_anonymously_text = fs_text_inline( 'Click here to use the plugin anonymously', 'click-here-to-use-plugin-anonymously', $slug );
echo sprintf( fs_text_inline( "You might have missed it, but you don't have to share any data and can just %s the opt-in.", 'dont-have-to-share-any-data', $slug ), "<a href='{$skip_url}'>{$skip_text}</a>" )
```
Fixed Code:
```php
<?php
/**
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* @var array $VARS
*/
$fs = freemius( $VARS['id'] );
$slug = $fs->get_slug();
$skip_url = fs_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $fs->get_unique_affix() . '_skip_activation' ) ), $fs->get_unique_affix() . '_skip_activation' );
$skip_text = strtolower( fs_text_x_inline( 'Skip', 'verb', 'skip', $slug ) );
$use_plugin_anonymously_text = fs_text_inline( 'Click here to use the plugin anonymously', 'click-here-to-use-plugin-anonymously', $slug );
echo sprintf( fs_text_inline( "You might have missed it, but you don't have to share any data and can just %s the opt-in.", 'dont-have-to-share-any-data', $slug ), "<a href='{$skip_url}'>{$skip_text}</a>" )
```
Explanation:
This diff contains only whitespace changes (line ending normalization from CRLF to LF). No code logic was modified, and no security fixes or vulnerabilities are present. The file maintains the same security posture before and after the change. The code uses appropriate WordPress functions (nonce handling via `fs_nonce_url`, text sanitization via `fs_text_inline`, `fs_text_x_inline`) for URL construction and output handling.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/index.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/index.php 2026-01-19 00:17:37.679046768 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No CWE/Vulnerability Identified - File: inc/freemius/templates/forms/index.php Old Code: ``` <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ``` <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace/formatting changes (likely tab vs space normalization). The file structure and content remain functionally identical. The file is a blank PHP file designed to prevent directory traversal attacks by existing without executable code - a common security practice. No vulnerabilities are introduced or fixed by this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/premium-versions-upgrade-handler.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/premium-versions-upgrade-handler.php 2026-01-19 00:17:37.679046768 +0000@@ -1,205 +1,205 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.0.2- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );- $slug = $fs->get_slug();-- $plugin_data = $fs->get_plugin_data();- $plugin_name = $plugin_data['Name'];- $plugin_basename = $fs->get_plugin_basename();-- $license = $fs->_get_license();-- if ( ! is_object( $license ) ) {- $purchase_url = $fs->pricing_url();- } else {- $subscription = $fs->_get_subscription( $license->id );-- $purchase_url = $fs->checkout_url(- is_object( $subscription ) ?- ( 1 == $subscription->billing_cycle ? WP_FS__PERIOD_MONTHLY : WP_FS__PERIOD_ANNUALLY ) :- WP_FS__PERIOD_LIFETIME,- false,- array( 'licenses' => $license->quota )- );- }-- $message = sprintf(- fs_text_inline( 'There is a new version of %s available.', 'new-version-available-message', $slug ) .- fs_text_inline( ' %s to access version %s security & feature updates, and support.', 'x-for-updates-and-support', $slug ),- '<span id="plugin_name"></span>',- sprintf(- '<a id="pricing_url" href="">%s</a>',- is_object( $license ) ?- fs_text_inline( 'Renew your license now', 'renew-license-now', $slug ) :- fs_text_inline( 'Buy a license now', 'buy-license-now', $slug )- ),- '<span id="new_version"></span>'- );-- $modal_content_html = "<p>{$message}</p>";-- $header_title = fs_text_inline( 'New Version Available', 'new-version-available', $slug );-- $renew_license_button_text = is_object( $license ) ?- fs_text_inline( 'Renew license', 'renew-license', $slug ) :- fs_text_inline( 'Buy license', 'buy-license', $slug );-- fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );-?>-<script type="text/javascript">-(function( $ ) {- $( document ).ready(function() {- if ( 0 === $( '.license-expired' ).length ) {- return;- }-- var modalContentHtml = <?php echo json_encode( $modal_content_html ) ?>,- modalHtml =- '<div class="fs-modal fs-modal-upgrade-premium-version">'- + ' <div class="fs-modal-dialog">'- + ' <div class="fs-modal-header">'- + ' <h4><?php echo esc_js( $header_title ) ?></h4>'- + ' <a href="!#" class="fs-close"><i class="dashicons dashicons-no" title="<?php echo esc_js( fs_text_x_inline( 'Dismiss', 'close a window', 'dismiss', $slug ) ) ?>"></i></a>'- + ' </div>'- + ' <div class="fs-modal-body">'- + ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>'- + ' </div>'- + ' <div class="fs-modal-footer">'- + ' <a class="button button-primary button-renew-license" tabindex="3" href="<?php echo $purchase_url ?>"><?php echo esc_js( $renew_license_button_text ) ?></a>'- + ' <button class="button button-secondary button-close" tabindex="4"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></button>'- + ' </div>'- + ' </div>'- + '</div>',- $modal = $( modalHtml ),- isPluginsPage = <?php echo Freemius::is_plugins_page() ? 'true' : 'false' ?>;-- $modal.appendTo( $( 'body' ) );-- function registerEventHandlers() {- $( 'body' ).on( 'click', '.license-expired', function( evt ) {- var $this = $( this );-- if ( ! $this.is( ':checked' ) ||- (- isPluginsPage &&- 'update-selected' !== $( '#bulk-action-selector-top' ).val() &&- 'update-selected' !== $( '#bulk-action-selector-bottom' ).val()- )- ) {- return true;- }-- evt.preventDefault();- evt.stopImmediatePropagation();-- showModal( $this );- });-- // If the user has clicked outside the window, close the modal.- $modal.on( 'click', '.fs-close, .button-secondary', function() {- closeModal();- return false;- });-- if ( isPluginsPage ) {- $( 'body' ).on( 'change', 'select[id*="bulk-action-selector"]', function() {- if ( 'update-selected' === $( this ).val() ) {- setTimeout(function() {- $( '.license-expired' ).prop( 'checked', false );- $( '[id*="select-all"]' ).prop( 'checked', false );- }, 0);- }- });- }-- $( 'body' ).on( 'click', '[id*="select-all"]', function( evt ) {- var $this = $( this );-- if ( ! $this.is( ':checked' ) ) {- return true;- }-- if ( isPluginsPage ) {- if ( 'update-selected' !== $( '#bulk-action-selector-top' ).val() &&- 'update-selected' !== $( '#bulk-action-selector-bottom' ).val() ) {- return true;- }- }-- var $table = $this.closest( 'table' ),- controlChecked = $this.prop( 'checked' ),- toggle = ( event.shiftKey || $this.data( 'wp-toggle' ) ),- $modules = $table.children( 'tbody' ).filter( ':visible' ).children().children( '.check-column' ).find( ':checkbox' ),- $modulesWithNonActiveLicense = $modules.filter( '.license-expired' );-- if ( 0 === $modulesWithNonActiveLicense.length ) {- /**- * It's possible that the context HTML table element doesn't have checkboxes with- * ".license-expired" class if for example only the themes table has such checkboxes and the user- * clicks on a "Select All" checkbox on the plugins table which has no such checkboxes.- *- * @author Leo Fajardo (@leorw)- */- return true;- } else if ( 1 === $modulesWithNonActiveLicense.length ) {- showModal( $modulesWithNonActiveLicense );- }-- /**- * Prevent the default WordPress handler from checking all checkboxes.- *- * @author Leo Fajardo (@leorw)- */- evt.stopImmediatePropagation();-- $modules.filter( ':not(.license-expired)' )- .prop( 'checked', function() {- if ( $( this ).is( ':hidden,:disabled' ) ) {- return false;- }-- if ( toggle ) {- return ! $( this ).prop( 'checked' );- } else if ( controlChecked ) {- return true;- }-- return false;- });-- return false;- });- }-- registerEventHandlers();-- function showModal( $module ) {- $modal.find( '#plugin_name' ).text( $module.data( 'plugin-name' ) );- $modal.find( '#pricing_url' ).attr( 'href', $module.data( 'pricing-url' ) );- $modal.find( '#new_version' ).text( $module.data( 'new-version' ) );-- // Display the dialog box.- $modal.addClass( 'active' );- $( 'body' ).addClass( 'has-fs-modal' );- }-- function closeModal() {- $modal.removeClass( 'active' );- $( 'body' ).removeClass( 'has-fs-modal' );- }- });-})( jQuery );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.0.2 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + $slug = $fs->get_slug(); + + $plugin_data = $fs->get_plugin_data(); + $plugin_name = $plugin_data['Name']; + $plugin_basename = $fs->get_plugin_basename(); + + $license = $fs->_get_license(); + + if ( ! is_object( $license ) ) { + $purchase_url = $fs->pricing_url(); + } else { + $subscription = $fs->_get_subscription( $license->id ); + + $purchase_url = $fs->checkout_url( + is_object( $subscription ) ? + ( 1 == $subscription->billing_cycle ? WP_FS__PERIOD_MONTHLY : WP_FS__PERIOD_ANNUALLY ) : + WP_FS__PERIOD_LIFETIME, + false, + array( 'licenses' => $license->quota ) + ); + } + + $message = sprintf( + fs_text_inline( 'There is a new version of %s available.', 'new-version-available-message', $slug ) . + fs_text_inline( ' %s to access version %s security & feature updates, and support.', 'x-for-updates-and-support', $slug ), + '<span id="plugin_name"></span>', + sprintf( + '<a id="pricing_url" href="">%s</a>', + is_object( $license ) ? + fs_text_inline( 'Renew your license now', 'renew-license-now', $slug ) : + fs_text_inline( 'Buy a license now', 'buy-license-now', $slug ) + ), + '<span id="new_version"></span>' + ); + + $modal_content_html = "<p>{$message}</p>"; + + $header_title = fs_text_inline( 'New Version Available', 'new-version-available', $slug ); + + $renew_license_button_text = is_object( $license ) ? + fs_text_inline( 'Renew license', 'renew-license', $slug ) : + fs_text_inline( 'Buy license', 'buy-license', $slug ); + + fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' ); +?> +<script type="text/javascript"> +(function( $ ) { + $( document ).ready(function() { + if ( 0 === $( '.license-expired' ).length ) { + return; + } + + var modalContentHtml = <?php echo json_encode( $modal_content_html ) ?>, + modalHtml = + '<div class="fs-modal fs-modal-upgrade-premium-version">' + + ' <div class="fs-modal-dialog">' + + ' <div class="fs-modal-header">' + + ' <h4><?php echo esc_js( $header_title ) ?></h4>' + + ' <a href="!#" class="fs-close"><i class="dashicons dashicons-no" title="<?php echo esc_js( fs_text_x_inline( 'Dismiss', 'close a window', 'dismiss', $slug ) ) ?>"></i></a>' + + ' </div>' + + ' <div class="fs-modal-body">' + + ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>' + + ' </div>' + + ' <div class="fs-modal-footer">' + + ' <a class="button button-primary button-renew-license" tabindex="3" href="<?php echo $purchase_url ?>"><?php echo esc_js( $renew_license_button_text ) ?></a>' + + ' <button class="button button-secondary button-close" tabindex="4"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></button>' + + ' </div>' + + ' </div>' + + '</div>', + $modal = $( modalHtml ), + isPluginsPage = <?php echo Freemius::is_plugins_page() ? 'true' : 'false' ?>; + + $modal.appendTo( $( 'body' ) ); + + function registerEventHandlers() { + $( 'body' ).on( 'click', '.license-expired', function( evt ) { + var $this = $( this ); + + if ( ! $this.is( ':checked' ) || + ( + isPluginsPage && + 'update-selected' !== $( '#bulk-action-selector-top' ).val() && + 'update-selected' !== $( '#bulk-action-selector-bottom' ).val() + ) + ) { + return true; + } + + evt.preventDefault(); + evt.stopImmediatePropagation(); + + showModal( $this ); + }); + + // If the user has clicked outside the window, close the modal. + $modal.on( 'click', '.fs-close, .button-secondary', function() { + closeModal(); + return false; + }); + + if ( isPluginsPage ) { + $( 'body' ).on( 'change', 'select[id*="bulk-action-selector"]', function() { + if ( 'update-selected' === $( this ).val() ) { + setTimeout(function() { + $( '.license-expired' ).prop( 'checked', false ); + $( '[id*="select-all"]' ).prop( 'checked', false ); + }, 0); + } + }); + } + + $( 'body' ).on( 'click', '[id*="select-all"]', function( evt ) { + var $this = $( this ); + + if ( ! $this.is( ':checked' ) ) { + return true; + } + + if ( isPluginsPage ) { + if ( 'update-selected' !== $( '#bulk-action-selector-top' ).val() && + 'update-selected' !== $( '#bulk-action-selector-bottom' ).val() ) { + return true; + } + } + + var $table = $this.closest( 'table' ), + controlChecked = $this.prop( 'checked' ), + toggle = ( event.shiftKey || $this.data( 'wp-toggle' ) ), + $modules = $table.children( 'tbody' ).filter( ':visible' ).children().children( '.check-column' ).find( ':checkbox' ), + $modulesWithNonActiveLicense = $modules.filter( '.license-expired' ); + + if ( 0 === $modulesWithNonActiveLicense.length ) { + /** + * It's possible that the context HTML table element doesn't have checkboxes with + * ".license-expired" class if for example only the themes table has such checkboxes and the user + * clicks on a "Select All" checkbox on the plugins table which has no such checkboxes. + * + * @author Leo Fajardo (@leorw) + */ + return true; + } else if ( 1 === $modulesWithNonActiveLicense.length ) { + showModal( $modulesWithNonActiveLicense ); + } + + /** + * Prevent the default WordPress handler from checking all checkboxes. + * + * @author Leo Fajardo (@leorw) + */ + evt.stopImmediatePropagation(); + + $modules.filter( ':not(.license-expired)' ) + .prop( 'checked', function() { + if ( $( this ).is( ':hidden,:disabled' ) ) { + return false; + } + + if ( toggle ) { + return ! $( this ).prop( 'checked' ); + } else if ( controlChecked ) { + return true; + } + + return false; + }); + + return false; + }); + } + + registerEventHandlers(); + + function showModal( $module ) { + $modal.find( '#plugin_name' ).text( $module.data( 'plugin-name' ) ); + $modal.find( '#pricing_url' ).attr( 'href', $module.data( 'pricing-url' ) ); + $modal.find( '#new_version' ).text( $module.data( 'new-version' ) ); + + // Display the dialog box. + $modal.addClass( 'active' ); + $( 'body' ).addClass( 'has-fs-modal' ); + } + + function closeModal() { + $modal.removeClass( 'active' ); + $( 'body' ).removeClass( 'has-fs-modal' ); + } + }); +})( jQuery ); </script>\ No newline at end of file
Analyzing the provided code diff for security vulnerabilities: **Vulnerability Existed: No** **Analysis Summary:** The diff shows only whitespace changes (line ending conversion from CRLF to LF). The actual code content remains identical between versions 1.2.11 and 1.2.12. **Details:** No security vulnerabilities were introduced or fixed in this change. The modifications consist entirely of: - Converting Windows-style line endings (CRLF) to Unix-style line endings (LF) - No functional code changes - No security-relevant logic modifications The code itself contains no new vulnerabilities, and the line ending normalization is a benign change that does not affect security posture.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/premium-versions-upgrade-metadata.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/premium-versions-upgrade-metadata.php 2026-01-19 00:17:37.679046768 +0000@@ -1,47 +1,47 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.0.2- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );-- $license = $fs->_get_license();-- if ( ! is_object( $license ) ) {- $purchase_url = $fs->pricing_url();- } else {- $subscription = $fs->_get_subscription( $license->id );-- $purchase_url = $fs->checkout_url(- is_object( $subscription ) ?- ( 1 == $subscription->billing_cycle ? WP_FS__PERIOD_MONTHLY : WP_FS__PERIOD_ANNUALLY ) :- WP_FS__PERIOD_LIFETIME,- false,- array( 'licenses' => $license->quota )- );- }-- $plugin_data = $fs->get_plugin_data();-?>-<script type="text/javascript">-(function( $ ) {- $( document ).ready(function() {- var $premiumVersionCheckbox = $( 'input[type="checkbox"][value="<?php echo $fs->get_plugin_basename() ?>"]' );-- $premiumVersionCheckbox.addClass( 'license-expired' );- $premiumVersionCheckbox.data( 'plugin-name', <?php echo json_encode( $plugin_data['Name'] ) ?> );- $premiumVersionCheckbox.data( 'pricing-url', <?php echo json_encode( $purchase_url ) ?> );- $premiumVersionCheckbox.data( 'new-version', <?php echo json_encode( $VARS['new_version'] ) ?> );- });-})( jQuery );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.0.2 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + + $license = $fs->_get_license(); + + if ( ! is_object( $license ) ) { + $purchase_url = $fs->pricing_url(); + } else { + $subscription = $fs->_get_subscription( $license->id ); + + $purchase_url = $fs->checkout_url( + is_object( $subscription ) ? + ( 1 == $subscription->billing_cycle ? WP_FS__PERIOD_MONTHLY : WP_FS__PERIOD_ANNUALLY ) : + WP_FS__PERIOD_LIFETIME, + false, + array( 'licenses' => $license->quota ) + ); + } + + $plugin_data = $fs->get_plugin_data(); +?> +<script type="text/javascript"> +(function( $ ) { + $( document ).ready(function() { + var $premiumVersionCheckbox = $( 'input[type="checkbox"][value="<?php echo $fs->get_plugin_basename() ?>"]' ); + + $premiumVersionCheckbox.addClass( 'license-expired' ); + $premiumVersionCheckbox.data( 'plugin-name', <?php echo json_encode( $plugin_data['Name'] ) ?> ); + $premiumVersionCheckbox.data( 'pricing-url', <?php echo json_encode( $purchase_url ) ?> ); + $premiumVersionCheckbox.data( 'new-version', <?php echo json_encode( $VARS['new_version'] ) ?> ); + }); +})( jQuery ); </script>\ No newline at end of file
Vulnerability Existed: no Cross-Site Scripting (XSS) - CWE-79 - inc/freemius/templates/forms/premium-versions-upgrade-metadata.php (Lines 40-45) Old Code: ```php var $premiumVersionCheckbox = $( 'input[type="checkbox"][value="<?php echo $fs->get_plugin_basename() ?>"]' ); $premiumVersionCheckbox.addClass( 'license-expired' ); $premiumVersionCheckbox.data( 'plugin-name', <?php echo json_encode( $plugin_data['Name'] ) ?> ); $premiumVersionCheckbox.data( 'pricing-url', <?php echo json_encode( $purchase_url ) ?> ); $premiumVersionCheckbox.data( 'new-version', <?php echo json_encode( $VARS['new_version'] ) ?> ); ``` Fixed Code: ```php var $premiumVersionCheckbox = $( 'input[type="checkbox"][value="<?php echo $fs->get_plugin_basename() ?>"]' ); $premiumVersionCheckbox.addClass( 'license-expired' ); $premiumVersionCheckbox.data( 'plugin-name', <?php echo json_encode( $plugin_data['Name'] ) ?> ); $premiumVersionCheckbox.data( 'pricing-url', <?php echo json_encode( $purchase_url ) ?> ); $premiumVersionCheckbox.data( 'new-version', <?php echo json_encode( $VARS['new_version'] ) ?> ); ``` Explanation: The diff shows only line ending changes (CRLF to LF conversion), with no substantive code modifications. The code does not contain XSS vulnerabilities because: 1. `json_encode()` is used for all dynamic data in JavaScript contexts (`$plugin_data['Name']`, `$purchase_url`, `$VARS['new_version']`), which properly escapes the data for safe JSON serialization 2. `$fs->get_plugin_basename()` is a WordPress plugin basename (e.g., "plugin-name/plugin-name.php"), which cannot contain user-controlled input or special characters that would break out of the HTML attribute context 3. The selector context is attribute-based and does not allow code injection No security fixes were applied in this diff - it is a formatting change only.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/resend-key.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/resend-key.php 2026-01-19 00:17:37.679046768 +0000@@ -1,250 +1,250 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );-- $slug = $fs->get_slug();-- $send_button_text = fs_text_inline( 'Send License Key', 'send-license-key', $slug );- $cancel_button_text = fs_text_inline( 'Cancel', 'cancel', $slug );- $email_address_placeholder = fs_esc_attr_inline( 'Email address', 'email-address', $slug );- $other_text = fs_text_inline( 'Other', 'other', $slug );-- $is_freemium = $fs->is_freemium();-- $send_button_text_html = esc_html($send_button_text);-- $button_html = <<< HTML-<div class="button-container">- <a href="#" class="button button-primary button-send-license-key" tabindex="2">{$send_button_text_html}</a>-</div>-HTML;-- if ( $is_freemium ) {- $current_user = Freemius::_get_current_wp_user();- $email = $current_user->user_email;- $esc_email = esc_attr( $email );- $form_html = <<< HTML-<div class="email-address-container">- <label><input name="email-address" type="radio" checked="checked" tabindex="1" value="{$esc_email}"> {$email}</label>- <label><input name="email-address" type="radio" tabindex="1" value="other">{$other_text}: <input class="email-address" type="text" placeholder="{$email_address_placeholder}"></label>-</div>-{$button_html}-HTML;- } else {- $email = '';- $form_html = <<< HTML-{$button_html}-<div class="email-address-container">- <input class="email-address" type="text" placeholder="{$email_address_placeholder}" tabindex="1">-</div>-HTML;- }-- $message_above_input_field = $fs->is_only_premium() ?- fs_esc_html_inline( "Enter the email address you've used during the purchase and we will resend you the license key.", 'ask-for-upgrade-email-address-premium-only', $slug ) :- fs_esc_html_inline( "Enter the email address you've used for the upgrade below and we will resend you the license key.", 'ask-for-upgrade-email-address', $slug );-- $modal_content_html = <<< HTML- <div class="notice notice-error inline license-resend-message"><p></p></div>- <p>{$message_above_input_field}</p>- <div class="input-container">- {$form_html}- </div>-HTML;-- fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );-?>-<script type="text/javascript">- (function ($) {- $(document).ready(function () {- var contentHtml = <?php echo json_encode( $modal_content_html ); ?>,- modalHtml =- '<div class="fs-modal fs-modal-license-key-resend <?php echo $is_freemium ? 'fs-freemium' : 'fs-premium' ?>">'- + ' <div class="fs-modal-dialog">'- + ' <div class="fs-modal-header">'- + ' <h4><?php echo esc_js( $send_button_text ) ?></h4>'- + ' <a href="#!" class="fs-close" tabindex="3" title="Close"><i class="dashicons dashicons-no" title="<?php echo esc_js( fs_text_x_inline( 'Dismiss', 'as close a window', 'dismiss', $slug ) ) ?>"></i></a>'- + ' </div>'- + ' <div class="fs-modal-body">'- + ' <div class="fs-modal-panel active">' + contentHtml + '</div>'- + ' </div>'- + ' </div>'- + '</div>',- $modal = $(modalHtml),- $sendButton = $modal.find('.button-send-license-key'),- $emailInput = $modal.find('input.email-address'),- $feedbackMessage = $modal.find('.license-resend-message'),- isFreemium = <?php echo json_encode( $is_freemium ) ?>,- userEmail = <?php echo json_encode( $email ) ?>,- moduleID = '<?php echo $fs->get_id() ?>',- isChild = false;--- $modal.appendTo($('body'));-- function registerEventHandlers() {- $('a.show-license-resend-modal-<?php echo $fs->get_unique_affix() ?>').click(function (evt) {- evt.preventDefault();-- showModal();- });-- if (isFreemium) {- $modal.on('change', 'input[type=radio][name=email-address]', function () {- updateButtonState();- });-- $modal.on('focus', 'input.email-address', function () {- // Check custom email radio button on email input focus.- $($modal.find('input[type=radio]')[1]).prop('checked', true);-- updateButtonState();- });- }-- $modal.on('input propertychange', 'input.email-address', function () {- updateButtonState();- });-- $modal.on('blur', 'input.email-address', function () {- updateButtonState();- });-- $modal.on('click', '.fs-close', function (){- closeModal();- return false;- });-- $modal.on('click', '.button', function (evt) {- evt.preventDefault();-- if ($(this).hasClass('disabled')) {- return;- }-- var email = getEmail();-- disableButton();-- if (!(-1 < email.indexOf('@'))) {- return;- }-- $.ajax({- url : <?php echo Freemius::ajax_url() ?>,- method : 'POST',- data : {- action : '<?php echo $fs->get_ajax_action( 'resend_license_key' ) ?>',- security : '<?php echo $fs->get_ajax_security( 'resend_license_key' ) ?>',- module_id : moduleID,- email : email- },- beforeSend: function () {- $sendButton.text('<?php fs_esc_js_echo_inline( 'Sending license key', 'sending-license-key', $slug ) ?>...');- },- success : function (result) {- var resultObj = $.parseJSON(result);- if (resultObj.success) {- closeModal();- } else {- showError(resultObj.error);- resetButton();- }- }- });- });- }-- registerEventHandlers();-- resetButton();-- function showModal() {- resetModal();-- // Display the dialog box.- $modal.addClass('active');-- if (!isFreemium)- $emailInput.focus();-- var $body = $('body');-- isChild = $body.hasClass('has-fs-modal');- if (isChild) {- return;- }-- $body.addClass('has-fs-modal');- }-- function closeModal() {- $modal.removeClass('active');-- // If child modal, do not remove the "has-fs-modal" class of the <body> element to keep its scrollbars hidden.- if (isChild) {- return;- }-- $('body').removeClass('has-fs-modal');- }-- function resetButton() {- updateButtonState();- $sendButton.text(<?php echo json_encode($send_button_text) ?>);- }-- function resetModal() {- hideError();- resetButton();- $emailInput.val('');- }-- function getEmail() {- var email = $emailInput.val().trim();-- if (isFreemium) {- if ('other' != $modal.find('input[type=radio][name=email-address]:checked').val()) {- email = userEmail;- }- }-- return email;- }-- function updateButtonState() {- /**- * If email address is not empty, enable the send license key button.- */- $sendButton.toggleClass('disabled', !( -1 < getEmail().indexOf('@') ));- }-- function disableButton() {- $sendButton.addClass('disabled');- }-- function hideError() {- $feedbackMessage.hide();- }-- function showError(msg) {- $feedbackMessage.find(' > p').html(msg);- $feedbackMessage.show();- }- });- })(jQuery);-</script>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + + $slug = $fs->get_slug(); + + $send_button_text = fs_text_inline( 'Send License Key', 'send-license-key', $slug ); + $cancel_button_text = fs_text_inline( 'Cancel', 'cancel', $slug ); + $email_address_placeholder = fs_esc_attr_inline( 'Email address', 'email-address', $slug ); + $other_text = fs_text_inline( 'Other', 'other', $slug ); + + $is_freemium = $fs->is_freemium(); + + $send_button_text_html = esc_html($send_button_text); + + $button_html = <<< HTML +<div class="button-container"> + <a href="#" class="button button-primary button-send-license-key" tabindex="2">{$send_button_text_html}</a> +</div> +HTML; + + if ( $is_freemium ) { + $current_user = Freemius::_get_current_wp_user(); + $email = $current_user->user_email; + $esc_email = esc_attr( $email ); + $form_html = <<< HTML +<div class="email-address-container"> + <label><input name="email-address" type="radio" checked="checked" tabindex="1" value="{$esc_email}"> {$email}</label> + <label><input name="email-address" type="radio" tabindex="1" value="other">{$other_text}: <input class="email-address" type="text" placeholder="{$email_address_placeholder}"></label> +</div> +{$button_html} +HTML; + } else { + $email = ''; + $form_html = <<< HTML +{$button_html} +<div class="email-address-container"> + <input class="email-address" type="text" placeholder="{$email_address_placeholder}" tabindex="1"> +</div> +HTML; + } + + $message_above_input_field = $fs->is_only_premium() ? + fs_esc_html_inline( "Enter the email address you've used during the purchase and we will resend you the license key.", 'ask-for-upgrade-email-address-premium-only', $slug ) : + fs_esc_html_inline( "Enter the email address you've used for the upgrade below and we will resend you the license key.", 'ask-for-upgrade-email-address', $slug ); + + $modal_content_html = <<< HTML + <div class="notice notice-error inline license-resend-message"><p></p></div> + <p>{$message_above_input_field}</p> + <div class="input-container"> + {$form_html} + </div> +HTML; + + fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' ); +?> +<script type="text/javascript"> + (function ($) { + $(document).ready(function () { + var contentHtml = <?php echo json_encode( $modal_content_html ); ?>, + modalHtml = + '<div class="fs-modal fs-modal-license-key-resend <?php echo $is_freemium ? 'fs-freemium' : 'fs-premium' ?>">' + + ' <div class="fs-modal-dialog">' + + ' <div class="fs-modal-header">' + + ' <h4><?php echo esc_js( $send_button_text ) ?></h4>' + + ' <a href="#!" class="fs-close" tabindex="3" title="Close"><i class="dashicons dashicons-no" title="<?php echo esc_js( fs_text_x_inline( 'Dismiss', 'as close a window', 'dismiss', $slug ) ) ?>"></i></a>' + + ' </div>' + + ' <div class="fs-modal-body">' + + ' <div class="fs-modal-panel active">' + contentHtml + '</div>' + + ' </div>' + + ' </div>' + + '</div>', + $modal = $(modalHtml), + $sendButton = $modal.find('.button-send-license-key'), + $emailInput = $modal.find('input.email-address'), + $feedbackMessage = $modal.find('.license-resend-message'), + isFreemium = <?php echo json_encode( $is_freemium ) ?>, + userEmail = <?php echo json_encode( $email ) ?>, + moduleID = '<?php echo $fs->get_id() ?>', + isChild = false; + + + $modal.appendTo($('body')); + + function registerEventHandlers() { + $('a.show-license-resend-modal-<?php echo $fs->get_unique_affix() ?>').click(function (evt) { + evt.preventDefault(); + + showModal(); + }); + + if (isFreemium) { + $modal.on('change', 'input[type=radio][name=email-address]', function () { + updateButtonState(); + }); + + $modal.on('focus', 'input.email-address', function () { + // Check custom email radio button on email input focus. + $($modal.find('input[type=radio]')[1]).prop('checked', true); + + updateButtonState(); + }); + } + + $modal.on('input propertychange', 'input.email-address', function () { + updateButtonState(); + }); + + $modal.on('blur', 'input.email-address', function () { + updateButtonState(); + }); + + $modal.on('click', '.fs-close', function (){ + closeModal(); + return false; + }); + + $modal.on('click', '.button', function (evt) { + evt.preventDefault(); + + if ($(this).hasClass('disabled')) { + return; + } + + var email = getEmail(); + + disableButton(); + + if (!(-1 < email.indexOf('@'))) { + return; + } + + $.ajax({ + url : <?php echo Freemius::ajax_url() ?>, + method : 'POST', + data : { + action : '<?php echo $fs->get_ajax_action( 'resend_license_key' ) ?>', + security : '<?php echo $fs->get_ajax_security( 'resend_license_key' ) ?>', + module_id : moduleID, + email : email + }, + beforeSend: function () { + $sendButton.text('<?php fs_esc_js_echo_inline( 'Sending license key', 'sending-license-key', $slug ) ?>...'); + }, + success : function (result) { + var resultObj = $.parseJSON(result); + if (resultObj.success) { + closeModal(); + } else { + showError(resultObj.error); + resetButton(); + } + } + }); + }); + } + + registerEventHandlers(); + + resetButton(); + + function showModal() { + resetModal(); + + // Display the dialog box. + $modal.addClass('active'); + + if (!isFreemium) + $emailInput.focus(); + + var $body = $('body'); + + isChild = $body.hasClass('has-fs-modal'); + if (isChild) { + return; + } + + $body.addClass('has-fs-modal'); + } + + function closeModal() { + $modal.removeClass('active'); + + // If child modal, do not remove the "has-fs-modal" class of the <body> element to keep its scrollbars hidden. + if (isChild) { + return; + } + + $('body').removeClass('has-fs-modal'); + } + + function resetButton() { + updateButtonState(); + $sendButton.text(<?php echo json_encode($send_button_text) ?>); + } + + function resetModal() { + hideError(); + resetButton(); + $emailInput.val(''); + } + + function getEmail() { + var email = $emailInput.val().trim(); + + if (isFreemium) { + if ('other' != $modal.find('input[type=radio][name=email-address]:checked').val()) { + email = userEmail; + } + } + + return email; + } + + function updateButtonState() { + /** + * If email address is not empty, enable the send license key button. + */ + $sendButton.toggleClass('disabled', !( -1 < getEmail().indexOf('@') )); + } + + function disableButton() { + $sendButton.addClass('disabled'); + } + + function hideError() { + $feedbackMessage.hide(); + } + + function showError(msg) { + $feedbackMessage.find(' > p').html(msg); + $feedbackMessage.show(); + } + }); + })(jQuery); +</script>
Vulnerability Existed: no Analysis Summary: The diff provided shows only whitespace changes (line ending conversion from CRLF to LF or similar line ending normalization). There are no functional code changes between the two versions of the file. The file contains the same PHP and JavaScript code in both versions: - Same HTML escaping functions (`esc_html`, `esc_attr`, `esc_js`) - Same security nonce handling (`$fs->get_ajax_security()`) - Same AJAX implementation with POST method - Same input validation logic - Same output encoding with `json_encode()` Since no actual code changes were made, no security vulnerabilities were introduced or fixed in this diff. The file maintains the same security posture in both versions.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/subscription-cancellation.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/subscription-cancellation.php 2026-01-19 00:17:37.679046768 +0000@@ -1,277 +1,277 @@-<?php-/**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.2.1- */--if ( ! defined( 'ABSPATH' ) ) {- exit;-}--/**- * @var array $VARS- */-$fs = freemius( $VARS['id'] );-$slug = $fs->get_slug();--/**- * @var FS_Plugin_License $license- */-$license = $VARS['license'];--$has_trial = $VARS['has_trial'];--$subscription_cancellation_context = $has_trial ?- fs_text_inline( 'trial', 'trial', $slug ) :- fs_text_inline( 'subscription', 'subscription', $slug );--$plan = $fs->get_plan();-$module_label = $fs->get_module_label( true );--if ( $VARS['is_license_deactivation'] ) {- $subscription_cancellation_text = '';-} else {- $subscription_cancellation_text = sprintf(- fs_text_inline(- "Deactivating or uninstalling the %s will automatically disable the license, which you'll be able to use on another site.",- 'deactivation-or-uninstall-message',- $slug- ),- $module_label- ) . ' ';-}-- $subscription_cancellation_text .= sprintf(- fs_text_inline(- 'In case you are NOT planning on using this %s on this site (or any other site) - would you like to cancel the %s as well?',- 'cancel-subscription-message',- $slug- ),- ( $VARS['is_license_deactivation'] ? fs_text_inline( 'license', 'license', $slug ) : $module_label ),- $subscription_cancellation_context-);--$cancel_subscription_action_label = sprintf(- fs_esc_html_inline(- "Cancel %s - I no longer need any security & feature updates, nor support for %s because I'm not planning to use the %s on this, or any other site.",- 'cancel-x',- $slug- ),- esc_html( $subscription_cancellation_context ),- sprintf( '<strong>%s</strong>', esc_html( $fs->get_plugin_title() ) ),- esc_html( $module_label )-);--$keep_subscription_active_action_label = esc_html( sprintf(- fs_text_inline(- "Don't cancel %s - I'm still interested in getting security & feature updates, as well as be able to contact support.",- 'dont-cancel-x',- $slug- ),- $subscription_cancellation_context-) );--$subscription_cancellation_text = esc_html( $subscription_cancellation_text );--$subscription_cancellation_html = <<< HTML- <div class="notice notice-error inline"><p></p></div><p>{$subscription_cancellation_text}</p>- <ul class="subscription-actions">- <li>- <label>- <input type="radio" name="cancel-subscription" value="false"/>- <span>{$keep_subscription_active_action_label}</span>- </label>- </li>- <li>- <label>- <input type="radio" name="cancel-subscription" value="true"/>- <span>{$cancel_subscription_action_label}</span>- </label>- </li>- </ul>-HTML;--$downgrading_plan_text = fs_text_inline( 'Downgrading your plan', 'downgrading-plan', $slug );-$cancelling_subscription_text = fs_text_inline( 'Cancelling the subscription', 'cancelling-subscription', $slug );-/* translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription' */-$downgrade_x_confirm_text = fs_text_inline( '%1$s will immediately stop all future recurring payments and your %2$s plan license will expire in %3$s.', 'downgrade-x-confirm', $slug );-$prices_increase_text = fs_text_inline( 'Please note that we will not be able to grandfather outdated pricing for renewals/new subscriptions after a cancellation. If you choose to renew the subscription manually in the future, after a price increase, which typically occurs once a year, you will be charged the updated price.', 'pricing-increase-warning', $slug );-$after_downgrade_non_blocking_text = fs_text_inline( 'You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support.', 'after-downgrade-non-blocking', $slug );-$after_downgrade_blocking_text = fs_text_inline( 'Once your license expires you can still use the Free version but you will NOT have access to the %s features.', 'after-downgrade-blocking', $slug );-$after_downgrade_blocking_text_premium_only = fs_text_inline( 'Once your license expires you will no longer be able to use the %s, unless you activate it again with a valid premium license.', 'after-downgrade-blocking-premium-only', $slug );--$subscription_cancellation_confirmation_message = $has_trial ?- fs_text_inline( 'Cancelling the trial will immediately block access to all premium features. Are you sure?', 'cancel-trial-confirm', $slug ) :- sprintf(- '%s %s %s %s',- sprintf(- $downgrade_x_confirm_text,- ($fs->is_only_premium() ? $cancelling_subscription_text : $downgrading_plan_text ),- $plan->title,- human_time_diff( time(), strtotime( $license->expiration ) )- ),- (- $license->is_block_features ?- (- $fs->is_only_premium() ?- sprintf( $after_downgrade_blocking_text_premium_only, $module_label ) :- sprintf( $after_downgrade_blocking_text, $plan->title )- ) :- sprintf( $after_downgrade_non_blocking_text, $plan->title, $fs->get_module_label( true ) )- ),- $prices_increase_text,- fs_esc_attr_inline( 'Are you sure you want to proceed?', 'proceed-confirmation', $slug )- );--fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );-?>-<script type="text/javascript">- (function( $ ) {- var modalHtml =- '<div class="fs-modal fs-modal-subscription-cancellation fs-modal-subscription-cancellation-<?php echo $fs->get_id() ?>">'- + ' <div class="fs-modal-dialog">'- + ' <div class="fs-modal-header">'- + ' <h4><?php echo esc_html( sprintf( fs_text_inline( 'Cancel %s?', 'cancel-x', $slug ), ucfirst( $subscription_cancellation_context ) ) ) ?></h4>'- + ' </div>'- + ' <div class="fs-modal-body">'- + ' <div class="fs-modal-panel active">' + <?php echo json_encode( $subscription_cancellation_html ) ?> + '<p class="fs-price-increase-warning" style="display: none;">' + <?php echo json_encode( $prices_increase_text ) ?> + '</p></div>'- + ' </div>'- + ' <div class="fs-modal-footer">'- + ' <a href="#" class="button button-secondary button-close"><?php fs_esc_attr_echo_inline( 'Cancel', 'cancel', $slug ) ?></a>'- + ' <a href="#" class="button button-primary button-deactivate disabled"><?php fs_esc_attr_echo_inline( 'Proceed', 'proceed', $slug ) ?></a>'- + ' </div>'- + ' </div>'- + '</div>',- $modal = $(modalHtml);-- $modal.appendTo($('body'));-- registerEventHandlers();-- function registerEventHandlers() {- $modal.on( 'showModal', function() {- showModal();- });-- $modal.on( 'closeModal', function() {- closeModal();- });-- $modal.on('click', '.fs-modal-footer .button', function (evt) {- evt.preventDefault();-- if ($(this).hasClass('disabled')) {- return;- }-- var _this = $(this),- subscriptionCancellationActionEventName = <?php echo json_encode( $fs->get_action_tag( 'subscription_cancellation_action' ) ) ?>;-- if ( _this.hasClass( 'button-primary' ) ) {- if ( 'true' !== $modal.find( 'input[name="cancel-subscription"]:checked' ).val() ) {- $modal.trigger( subscriptionCancellationActionEventName, false );- } else {- if ( confirm( <?php echo json_encode( $subscription_cancellation_confirmation_message ) ?> ) ) {- $modal.trigger( subscriptionCancellationActionEventName, true );- }- }- }- });-- $modal.on('click', 'input[type="radio"]', function () {- var- $selectedOption = $( this ),- $primaryButton = $modal.find( '.button-primary' ),- isSelected = ( 'true' === $selectedOption.val() );-- if ( isSelected ) {- $primaryButton.html( <?php echo json_encode( sprintf(- fs_text_inline( 'Cancel %s & Proceed', 'cancel-x-and-proceed', $slug ),- ucfirst( $subscription_cancellation_context )- ) ) ?> );-- $modal.find('.fs-price-increase-warning').show();- } else {- $primaryButton.html( <?php fs_json_encode_echo_inline( 'Proceed', 'proceed', $slug ) ?> );- $modal.find('.fs-price-increase-warning').hide();- }-- $primaryButton.toggleClass( 'warn', isSelected );- $primaryButton.removeClass( 'disabled' );- });-- // If the user has clicked outside the window, cancel it.- $modal.on('click', function (evt) {- var $target = $(evt.target);-- // If the user has clicked anywhere in the modal dialog, just return.- if ($target.hasClass('fs-modal-body') || $target.hasClass('fs-modal-footer')) {- return;- }-- // If the user has not clicked the close button and the clicked element is inside the modal dialog, just return.- if (- ( ! $target.hasClass( 'button-close' ) ) &&- ( $target.parents( '.fs-modal-body' ).length > 0 || $target.parents( '.fs-modal-footer' ).length > 0 )- ) {- return;- }-- closeModal();-- return false;- });- }-- function showModal() {- resetModal();-- // Display the dialog box.- $modal.addClass('active');-- $('body').addClass('has-fs-modal');- }-- function closeModal() {- var activeModalsCount = $( '.fs-modal.active' ).length;-- $modal.removeClass('active');-- // If child modal, do not remove the "has-fs-modal" class of the <body> element to keep its scrollbars hidden.- if ( activeModalsCount > 1 ) {- return;- }-- $('body').removeClass('has-fs-modal');- }-- function resetModal() {- updateButtonLabels();-- if ( 0 === $modal.find( '.subscription-actions' ).length ) {- $modal.find('.button-deactivate').removeClass('disabled');- } else {- $modal.find('.button-deactivate').addClass('disabled');- }-- $modal.find('.fs-price-increase-warning').hide();-- // Uncheck all radio buttons.- $modal.find('input[type="radio"]').prop('checked', false);-- $modal.find('.message').hide();- }-- function showMessage(message) {- $modal.find('.message').text(message).show();- }-- function updateButtonLabels() {- $modal.find('.button-primary').text( <?php fs_json_encode_echo_inline( 'Proceed', 'proceed', $slug ) ?> );-- $modal.find('.button-secondary').text( <?php fs_json_encode_echo_inline( 'Cancel', 'cancel', $slug ) ?> );- }- })( jQuery );+<?php +/** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.2.1 + */ + +if ( ! defined( 'ABSPATH' ) ) { + exit; +} + +/** + * @var array $VARS + */ +$fs = freemius( $VARS['id'] ); +$slug = $fs->get_slug(); + +/** + * @var FS_Plugin_License $license + */ +$license = $VARS['license']; + +$has_trial = $VARS['has_trial']; + +$subscription_cancellation_context = $has_trial ? + fs_text_inline( 'trial', 'trial', $slug ) : + fs_text_inline( 'subscription', 'subscription', $slug ); + +$plan = $fs->get_plan(); +$module_label = $fs->get_module_label( true ); + +if ( $VARS['is_license_deactivation'] ) { + $subscription_cancellation_text = ''; +} else { + $subscription_cancellation_text = sprintf( + fs_text_inline( + "Deactivating or uninstalling the %s will automatically disable the license, which you'll be able to use on another site.", + 'deactivation-or-uninstall-message', + $slug + ), + $module_label + ) . ' '; +} + + $subscription_cancellation_text .= sprintf( + fs_text_inline( + 'In case you are NOT planning on using this %s on this site (or any other site) - would you like to cancel the %s as well?', + 'cancel-subscription-message', + $slug + ), + ( $VARS['is_license_deactivation'] ? fs_text_inline( 'license', 'license', $slug ) : $module_label ), + $subscription_cancellation_context +); + +$cancel_subscription_action_label = sprintf( + fs_esc_html_inline( + "Cancel %s - I no longer need any security & feature updates, nor support for %s because I'm not planning to use the %s on this, or any other site.", + 'cancel-x', + $slug + ), + esc_html( $subscription_cancellation_context ), + sprintf( '<strong>%s</strong>', esc_html( $fs->get_plugin_title() ) ), + esc_html( $module_label ) +); + +$keep_subscription_active_action_label = esc_html( sprintf( + fs_text_inline( + "Don't cancel %s - I'm still interested in getting security & feature updates, as well as be able to contact support.", + 'dont-cancel-x', + $slug + ), + $subscription_cancellation_context +) ); + +$subscription_cancellation_text = esc_html( $subscription_cancellation_text ); + +$subscription_cancellation_html = <<< HTML + <div class="notice notice-error inline"><p></p></div><p>{$subscription_cancellation_text}</p> + <ul class="subscription-actions"> + <li> + <label> + <input type="radio" name="cancel-subscription" value="false"/> + <span>{$keep_subscription_active_action_label}</span> + </label> + </li> + <li> + <label> + <input type="radio" name="cancel-subscription" value="true"/> + <span>{$cancel_subscription_action_label}</span> + </label> + </li> + </ul> +HTML; + +$downgrading_plan_text = fs_text_inline( 'Downgrading your plan', 'downgrading-plan', $slug ); +$cancelling_subscription_text = fs_text_inline( 'Cancelling the subscription', 'cancelling-subscription', $slug ); +/* translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription' */ +$downgrade_x_confirm_text = fs_text_inline( '%1$s will immediately stop all future recurring payments and your %2$s plan license will expire in %3$s.', 'downgrade-x-confirm', $slug ); +$prices_increase_text = fs_text_inline( 'Please note that we will not be able to grandfather outdated pricing for renewals/new subscriptions after a cancellation. If you choose to renew the subscription manually in the future, after a price increase, which typically occurs once a year, you will be charged the updated price.', 'pricing-increase-warning', $slug ); +$after_downgrade_non_blocking_text = fs_text_inline( 'You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support.', 'after-downgrade-non-blocking', $slug ); +$after_downgrade_blocking_text = fs_text_inline( 'Once your license expires you can still use the Free version but you will NOT have access to the %s features.', 'after-downgrade-blocking', $slug ); +$after_downgrade_blocking_text_premium_only = fs_text_inline( 'Once your license expires you will no longer be able to use the %s, unless you activate it again with a valid premium license.', 'after-downgrade-blocking-premium-only', $slug ); + +$subscription_cancellation_confirmation_message = $has_trial ? + fs_text_inline( 'Cancelling the trial will immediately block access to all premium features. Are you sure?', 'cancel-trial-confirm', $slug ) : + sprintf( + '%s %s %s %s', + sprintf( + $downgrade_x_confirm_text, + ($fs->is_only_premium() ? $cancelling_subscription_text : $downgrading_plan_text ), + $plan->title, + human_time_diff( time(), strtotime( $license->expiration ) ) + ), + ( + $license->is_block_features ? + ( + $fs->is_only_premium() ? + sprintf( $after_downgrade_blocking_text_premium_only, $module_label ) : + sprintf( $after_downgrade_blocking_text, $plan->title ) + ) : + sprintf( $after_downgrade_non_blocking_text, $plan->title, $fs->get_module_label( true ) ) + ), + $prices_increase_text, + fs_esc_attr_inline( 'Are you sure you want to proceed?', 'proceed-confirmation', $slug ) + ); + +fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' ); +?> +<script type="text/javascript"> + (function( $ ) { + var modalHtml = + '<div class="fs-modal fs-modal-subscription-cancellation fs-modal-subscription-cancellation-<?php echo $fs->get_id() ?>">' + + ' <div class="fs-modal-dialog">' + + ' <div class="fs-modal-header">' + + ' <h4><?php echo esc_html( sprintf( fs_text_inline( 'Cancel %s?', 'cancel-x', $slug ), ucfirst( $subscription_cancellation_context ) ) ) ?></h4>' + + ' </div>' + + ' <div class="fs-modal-body">' + + ' <div class="fs-modal-panel active">' + <?php echo json_encode( $subscription_cancellation_html ) ?> + '<p class="fs-price-increase-warning" style="display: none;">' + <?php echo json_encode( $prices_increase_text ) ?> + '</p></div>' + + ' </div>' + + ' <div class="fs-modal-footer">' + + ' <a href="#" class="button button-secondary button-close"><?php fs_esc_attr_echo_inline( 'Cancel', 'cancel', $slug ) ?></a>' + + ' <a href="#" class="button button-primary button-deactivate disabled"><?php fs_esc_attr_echo_inline( 'Proceed', 'proceed', $slug ) ?></a>' + + ' </div>' + + ' </div>' + + '</div>', + $modal = $(modalHtml); + + $modal.appendTo($('body')); + + registerEventHandlers(); + + function registerEventHandlers() { + $modal.on( 'showModal', function() { + showModal(); + }); + + $modal.on( 'closeModal', function() { + closeModal(); + }); + + $modal.on('click', '.fs-modal-footer .button', function (evt) { + evt.preventDefault(); + + if ($(this).hasClass('disabled')) { + return; + } + + var _this = $(this), + subscriptionCancellationActionEventName = <?php echo json_encode( $fs->get_action_tag( 'subscription_cancellation_action' ) ) ?>; + + if ( _this.hasClass( 'button-primary' ) ) { + if ( 'true' !== $modal.find( 'input[name="cancel-subscription"]:checked' ).val() ) { + $modal.trigger( subscriptionCancellationActionEventName, false ); + } else { + if ( confirm( <?php echo json_encode( $subscription_cancellation_confirmation_message ) ?> ) ) { + $modal.trigger( subscriptionCancellationActionEventName, true ); + } + } + } + }); + + $modal.on('click', 'input[type="radio"]', function () { + var + $selectedOption = $( this ), + $primaryButton = $modal.find( '.button-primary' ), + isSelected = ( 'true' === $selectedOption.val() ); + + if ( isSelected ) { + $primaryButton.html( <?php echo json_encode( sprintf( + fs_text_inline( 'Cancel %s & Proceed', 'cancel-x-and-proceed', $slug ), + ucfirst( $subscription_cancellation_context ) + ) ) ?> ); + + $modal.find('.fs-price-increase-warning').show(); + } else { + $primaryButton.html( <?php fs_json_encode_echo_inline( 'Proceed', 'proceed', $slug ) ?> ); + $modal.find('.fs-price-increase-warning').hide(); + } + + $primaryButton.toggleClass( 'warn', isSelected ); + $primaryButton.removeClass( 'disabled' ); + }); + + // If the user has clicked outside the window, cancel it. + $modal.on('click', function (evt) { + var $target = $(evt.target); + + // If the user has clicked anywhere in the modal dialog, just return. + if ($target.hasClass('fs-modal-body') || $target.hasClass('fs-modal-footer')) { + return; + } + + // If the user has not clicked the close button and the clicked element is inside the modal dialog, just return. + if ( + ( ! $target.hasClass( 'button-close' ) ) && + ( $target.parents( '.fs-modal-body' ).length > 0 || $target.parents( '.fs-modal-footer' ).length > 0 ) + ) { + return; + } + + closeModal(); + + return false; + }); + } + + function showModal() { + resetModal(); + + // Display the dialog box. + $modal.addClass('active'); + + $('body').addClass('has-fs-modal'); + } + + function closeModal() { + var activeModalsCount = $( '.fs-modal.active' ).length; + + $modal.removeClass('active'); + + // If child modal, do not remove the "has-fs-modal" class of the <body> element to keep its scrollbars hidden. + if ( activeModalsCount > 1 ) { + return; + } + + $('body').removeClass('has-fs-modal'); + } + + function resetModal() { + updateButtonLabels(); + + if ( 0 === $modal.find( '.subscription-actions' ).length ) { + $modal.find('.button-deactivate').removeClass('disabled'); + } else { + $modal.find('.button-deactivate').addClass('disabled'); + } + + $modal.find('.fs-price-increase-warning').hide(); + + // Uncheck all radio buttons. + $modal.find('input[type="radio"]').prop('checked', false); + + $modal.find('.message').hide(); + } + + function showMessage(message) { + $modal.find('.message').text(message).show(); + } + + function updateButtonLabels() { + $modal.find('.button-primary').text( <?php fs_json_encode_echo_inline( 'Proceed', 'proceed', $slug ) ?> ); + + $modal.find('.button-secondary').text( <?php fs_json_encode_echo_inline( 'Cancel', 'cancel', $slug ) ?> ); + } + })( jQuery ); </script>\ No newline at end of file
Vulnerability Existed: no No Vulnerabilities Detected - inc/freemius/templates/forms/subscription-cancellation.php Explanation: This diff shows a line-ending normalization change (converting CRLF to LF line endings) throughout the file. No actual code logic has been modified. The file content remains identical in terms of functionality and security posture. All existing security measures are preserved: - Output escaping functions remain in place (esc_html, esc_attr, json_encode) - No new data inputs or processing logic were introduced - No removal or modification of security-related code - The change is purely a formatting/normalization update with no security implications
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/forms/trial-start.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/forms/trial-start.php 2026-01-19 00:17:37.679046768 +0000@@ -1,181 +1,181 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );- $slug = $fs->get_slug();-- $message_header = sprintf(- /* translators: %1$s: Number of trial days; %2$s: Plan name; */- fs_text_inline( 'You are 1-click away from starting your %1$s-day free trial of the %2$s plan.', 'start-trial-prompt-header', $slug ),- '<span class="var-trial_period"></span>',- '<span class="var-plan_title"></span>'- );- $message_content = sprintf(- /* translators: %s: Link to freemius.com */- fs_text_inline( 'For compliance with the WordPress.org guidelines, before we start the trial we ask that you opt in with your user and non-sensitive site information, allowing the %s to periodically send data to %s to check for version updates and to validate your trial.', 'start-trial-prompt-message', $slug ),- $fs->get_module_type(),- sprintf(- '<a href="%s" target="_blank" rel="noopener">%s</a>',- 'https://freemius.com',- 'freemius.com'- )- );-- $modal_content_html = <<< HTML- <div class="notice notice-error inline"><p></p></div>- <h3>{$message_header}</h3>- <p>{$message_content}</p>-HTML;-- fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );-?>-<script type="text/javascript">- (function ($) {- $(document).ready(function () {- var modalContentHtml = <?php echo json_encode( $modal_content_html ); ?>,- modalHtml =- '<div class="fs-modal fs-modal-license-key-resend">'- + ' <div class="fs-modal-dialog">'- + ' <div class="fs-modal-header">'- + ' <h4><?php echo esc_js( fs_text_x_inline( 'Start free trial', 'call to action', 'start-free-trial', $slug ) ) ?></h4>'- + ' </div>'- + ' <div class="fs-modal-body">' + modalContentHtml + '</div>'- + ' <div class="fs-modal-footer">'- + ' <button class="button button-secondary button-close">' + <?php fs_json_encode_echo_inline( 'Cancel', 'cancel', $slug ) ?> +'</button>'- + ' <button class="button button-primary button-connect">' + <?php fs_json_encode_echo_inline( 'Approve & Start Trial', 'approve-start-trial', $slug ) ?> +'</button>'- + ' </div>'- + ' </div>'- + '</div>',- $modal = $( modalHtml ),- trialData;-- $modal.appendTo($('body'));-- var $errorNotice = $modal.find('.notice-error');-- registerEventHandlers();-- function registerEventHandlers() {- $modal.on('click', '.button-close', function () {- closeModal();- return false;- });-- $modal.on('click', '.button-connect', function (evt) {- evt.preventDefault();-- var $button = $(this);-- $.ajax({- url : <?php echo Freemius::ajax_url() ?>,- method : 'POST',- data : {- action : '<?php echo $fs->get_ajax_action( 'start_trial' ) ?>',- security : '<?php echo $fs->get_ajax_security( 'start_trial' ) ?>',- module_id: '<?php echo $fs->get_id() ?>',- trial : trialData- },- beforeSend: function () {- // Disable all buttons during trial activation.- $modal.find('.button').prop('disabled', true);-- $button.text(<?php fs_json_encode_echo_inline( 'Starting trial', 'starting-trial', $slug ) ?> + '...');-- setLoadingMode();- },- success : function (resultObj) {- if (resultObj.success) {- $button.text(<?php fs_json_encode_echo_inline( 'Please wait', 'please-wait', $slug ) ?> + '...');-- // Redirect to the "Account" page and sync the license.- window.location.href = resultObj.data.next_page;- } else {- $button.text(<?php fs_json_encode_echo( 'approve-start-trial', $slug ) ?>);-- resetLoadingMode();- showError(resultObj.error);- }- }- });- });- }-- window.openTrialConfirmationModal = function showModal(data) {- resetModal();-- // Display the dialog box.- $modal.addClass('active');-- trialData = data;-- var $modalBody = $modal.find('.fs-modal-body'),- $var;-- for (var key in data) {- if (data.hasOwnProperty(key)) {- $var = $modalBody.find('.var-' + key);-- if ($var.length > 0)- $var.html(data[key]);- }- }-- $('body').addClass('has-fs-modal');- };-- function closeModal() {- $modal.removeClass('active');-- $('body').removeClass('has-fs-modal');- }-- function resetModal() {- hideError();- }-- function hideError() {- $errorNotice.hide();- }-- function setLoadingMode() {- $modal.find('.button')- // Re-enable all buttons.- .prop('disabled', trialData)- // Stop loading cursor.- .css({'cursor': 'wait'});-- // Stop loading cursor.- $(document.body).css({'cursor': 'wait'});- }-- function resetLoadingMode() {- $modal.find('.button')- // Re-enable all buttons.- .prop('disabled', false)- // Stop loading cursor.- .css({'cursor': 'initial'});-- // Stop loading cursor.- $(document.body).css({'cursor': 'initial'});- }-- function showError(msg) {- $errorNotice.find(' > p').html(msg);- $errorNotice.show();- }- });- })(jQuery);-</script>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + $slug = $fs->get_slug(); + + $message_header = sprintf( + /* translators: %1$s: Number of trial days; %2$s: Plan name; */ + fs_text_inline( 'You are 1-click away from starting your %1$s-day free trial of the %2$s plan.', 'start-trial-prompt-header', $slug ), + '<span class="var-trial_period"></span>', + '<span class="var-plan_title"></span>' + ); + $message_content = sprintf( + /* translators: %s: Link to freemius.com */ + fs_text_inline( 'For compliance with the WordPress.org guidelines, before we start the trial we ask that you opt in with your user and non-sensitive site information, allowing the %s to periodically send data to %s to check for version updates and to validate your trial.', 'start-trial-prompt-message', $slug ), + $fs->get_module_type(), + sprintf( + '<a href="%s" target="_blank" rel="noopener">%s</a>', + 'https://freemius.com', + 'freemius.com' + ) + ); + + $modal_content_html = <<< HTML + <div class="notice notice-error inline"><p></p></div> + <h3>{$message_header}</h3> + <p>{$message_content}</p> +HTML; + + fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' ); +?> +<script type="text/javascript"> + (function ($) { + $(document).ready(function () { + var modalContentHtml = <?php echo json_encode( $modal_content_html ); ?>, + modalHtml = + '<div class="fs-modal fs-modal-license-key-resend">' + + ' <div class="fs-modal-dialog">' + + ' <div class="fs-modal-header">' + + ' <h4><?php echo esc_js( fs_text_x_inline( 'Start free trial', 'call to action', 'start-free-trial', $slug ) ) ?></h4>' + + ' </div>' + + ' <div class="fs-modal-body">' + modalContentHtml + '</div>' + + ' <div class="fs-modal-footer">' + + ' <button class="button button-secondary button-close">' + <?php fs_json_encode_echo_inline( 'Cancel', 'cancel', $slug ) ?> +'</button>' + + ' <button class="button button-primary button-connect">' + <?php fs_json_encode_echo_inline( 'Approve & Start Trial', 'approve-start-trial', $slug ) ?> +'</button>' + + ' </div>' + + ' </div>' + + '</div>', + $modal = $( modalHtml ), + trialData; + + $modal.appendTo($('body')); + + var $errorNotice = $modal.find('.notice-error'); + + registerEventHandlers(); + + function registerEventHandlers() { + $modal.on('click', '.button-close', function () { + closeModal(); + return false; + }); + + $modal.on('click', '.button-connect', function (evt) { + evt.preventDefault(); + + var $button = $(this); + + $.ajax({ + url : <?php echo Freemius::ajax_url() ?>, + method : 'POST', + data : { + action : '<?php echo $fs->get_ajax_action( 'start_trial' ) ?>', + security : '<?php echo $fs->get_ajax_security( 'start_trial' ) ?>', + module_id: '<?php echo $fs->get_id() ?>', + trial : trialData + }, + beforeSend: function () { + // Disable all buttons during trial activation. + $modal.find('.button').prop('disabled', true); + + $button.text(<?php fs_json_encode_echo_inline( 'Starting trial', 'starting-trial', $slug ) ?> + '...'); + + setLoadingMode(); + }, + success : function (resultObj) { + if (resultObj.success) { + $button.text(<?php fs_json_encode_echo_inline( 'Please wait', 'please-wait', $slug ) ?> + '...'); + + // Redirect to the "Account" page and sync the license. + window.location.href = resultObj.data.next_page; + } else { + $button.text(<?php fs_json_encode_echo( 'approve-start-trial', $slug ) ?>); + + resetLoadingMode(); + showError(resultObj.error); + } + } + }); + }); + } + + window.openTrialConfirmationModal = function showModal(data) { + resetModal(); + + // Display the dialog box. + $modal.addClass('active'); + + trialData = data; + + var $modalBody = $modal.find('.fs-modal-body'), + $var; + + for (var key in data) { + if (data.hasOwnProperty(key)) { + $var = $modalBody.find('.var-' + key); + + if ($var.length > 0) + $var.html(data[key]); + } + } + + $('body').addClass('has-fs-modal'); + }; + + function closeModal() { + $modal.removeClass('active'); + + $('body').removeClass('has-fs-modal'); + } + + function resetModal() { + hideError(); + } + + function hideError() { + $errorNotice.hide(); + } + + function setLoadingMode() { + $modal.find('.button') + // Re-enable all buttons. + .prop('disabled', trialData) + // Stop loading cursor. + .css({'cursor': 'wait'}); + + // Stop loading cursor. + $(document.body).css({'cursor': 'wait'}); + } + + function resetLoadingMode() { + $modal.find('.button') + // Re-enable all buttons. + .prop('disabled', false) + // Stop loading cursor. + .css({'cursor': 'initial'}); + + // Stop loading cursor. + $(document.body).css({'cursor': 'initial'}); + } + + function showError(msg) { + $errorNotice.find(' > p').html(msg); + $errorNotice.show(); + } + }); + })(jQuery); +</script>
Vulnerability Existed: no
Analysis: The provided diff shows only line ending changes (CRLF to LF conversion) between version 1.2.11 and 1.2.12. The actual code content remains identical - no functional changes, security patches, or code modifications were made.
The file contains the following security considerations that were already present and remain unchanged:
1. **Line 103** - `$errorNotice.find(' > p').html(msg);` - Uses `.html()` to insert the error message. This could be vulnerable to XSS if `msg` contains unsanitized user input, but this depends on how `resultObj.error` is sanitized server-side.
2. **Line 130** - `$var.html(data[key]);` - Uses `.html()` to insert data values. Potential XSS vulnerability if `data` contains unsanitized values.
3. **Line 102** - `window.location.href = resultObj.data.next_page;` - Potential open redirect if `next_page` is not validated server-side.
However, since the diff contains only whitespace/line ending changes with no actual code modifications, there are **no new security fixes** introduced in this update.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/gdpr-optin-js.php 2026-01-19 00:16:00.465015933 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/gdpr-optin-js.php 2026-01-19 00:17:37.679046768 +0000@@ -1,67 +1,67 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.1.0- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- */- $fs = freemius( $VARS['id'] );-?>-<script type="text/javascript">- (function( $ ) {- $( document ).ready(function() {- var $gdprOptinNotice = $( 'div[data-id^="gdpr_optin_actions"]' );- if ( 0 === $gdprOptinNotice.length ) {- return;- }-- $gdprOptinNotice.on( 'click', '.button', function() {- var- $this = $( this ),- allowMarketing = $this.hasClass( 'allow-marketing' ),- cursor = $this.css( 'cursor' ),- $products = $gdprOptinNotice.find( 'span[data-plugin-id]' ),- pluginIDs = [],- ajaxUrl = <?php echo Freemius::ajax_url() ?>;-- if ( $products.length > 0 ) {- $products.each(function() {- pluginIDs.push( $( this ).data( 'plugin-id' ) );- });- }-- $.ajax({- url : ajaxUrl + (ajaxUrl.includes('?') ? '&' : '?') + $.param({- action : '<?php echo $fs->get_ajax_action( 'gdpr_optin_action' ) ?>',- security : '<?php echo $fs->get_ajax_security( 'gdpr_optin_action' ) ?>',- module_id: '<?php echo $fs->get_id() ?>'- }),- method : 'POST',- data : {- is_marketing_allowed: allowMarketing,- plugin_ids : pluginIDs- },- beforeSend: function() {- $this.text( <?php fs_json_encode_echo_inline( 'Thanks, please wait', 'thanks-please-wait', $fs->get_slug() ) ?> + '...' );- $this.css({'cursor': 'wait'});-- $gdprOptinNotice.find( '.button' ).addClass( 'disabled' );- },- complete : function() {- $this.css({'cursor': cursor});-- $gdprOptinNotice.remove();- }- });- });- });- })( jQuery );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.1.0 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + */ + $fs = freemius( $VARS['id'] ); +?> +<script type="text/javascript"> + (function( $ ) { + $( document ).ready(function() { + var $gdprOptinNotice = $( 'div[data-id^="gdpr_optin_actions"]' ); + if ( 0 === $gdprOptinNotice.length ) { + return; + } + + $gdprOptinNotice.on( 'click', '.button', function() { + var + $this = $( this ), + allowMarketing = $this.hasClass( 'allow-marketing' ), + cursor = $this.css( 'cursor' ), + $products = $gdprOptinNotice.find( 'span[data-plugin-id]' ), + pluginIDs = [], + ajaxUrl = <?php echo Freemius::ajax_url() ?>; + + if ( $products.length > 0 ) { + $products.each(function() { + pluginIDs.push( $( this ).data( 'plugin-id' ) ); + }); + } + + $.ajax({ + url : ajaxUrl + (ajaxUrl.includes('?') ? '&' : '?') + $.param({ + action : '<?php echo $fs->get_ajax_action( 'gdpr_optin_action' ) ?>', + security : '<?php echo $fs->get_ajax_security( 'gdpr_optin_action' ) ?>', + module_id: '<?php echo $fs->get_id() ?>' + }), + method : 'POST', + data : { + is_marketing_allowed: allowMarketing, + plugin_ids : pluginIDs + }, + beforeSend: function() { + $this.text( <?php fs_json_encode_echo_inline( 'Thanks, please wait', 'thanks-please-wait', $fs->get_slug() ) ?> + '...' ); + $this.css({'cursor': 'wait'}); + + $gdprOptinNotice.find( '.button' ).addClass( 'disabled' ); + }, + complete : function() { + $this.css({'cursor': cursor}); + + $gdprOptinNotice.remove(); + } + }); + }); + }); + })( jQuery ); </script>\ No newline at end of file
Vulnerability Existed: no No Security Vulnerabilities Detected - inc/freemius/templates/gdpr-optin-js.php Explanation: This diff only contains line ending changes (converting from LF to CRLF or vice versa). The actual code content remains identical between versions 1.2.11 and 1.2.12. No functional code modifications were made, and therefore no security vulnerabilities were introduced or fixed. The file maintains its existing security posture: - AJAX requests include proper WordPress nonce security tokens via `$fs->get_ajax_security()` - Action validation is in place via `$fs->get_ajax_action()` - Module ID is properly transmitted - No new injection vectors or unsafe operations were introduced The diff represents a purely cosmetic change with no security impact.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/index.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/index.php 2026-01-19 00:17:37.679046768 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No CWE Applicable - File: inc/freemius/templates/index.php Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace/formatting changes (conversion of tabs to spaces or vice versa). The file remains functionally identical - it is an index.php file with no executable code, designed only to prevent directory listing on unprotected servers. No security vulnerabilities are introduced or fixed in this change. The file's purpose (blocking file structure exposure) is already achieved through its existence as an empty PHP file, and no modifications to that behavior have been made.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/js/index.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/js/index.php 2026-01-19 00:17:37.679046768 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no
No CWE - N/A - inc/freemius/templates/js/index.php
N/A
N/A
Explanation:
This diff contains only whitespace normalization changes (trailing whitespace removal/standardization). The file is a PHP index file that intentionally contains no executable code ("Silence is golden" is a WordPress convention for empty index files to prevent directory listing). There are no security vulnerabilities introduced, removed, or present in this change. The modification is purely a code style/formatting adjustment with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/js/jquery.content-change.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/js/jquery.content-change.php 2026-01-19 00:17:37.679046768 +0000@@ -1,58 +1,58 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.2.7- */- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-?>-<script type="text/javascript">- (function ($) {- if ($.fn.contentChange)- return;-- /**- * Content change event listener.- *- * @url http://stackoverflow.com/questions/3233991/jquery-watch-div/3234646#3234646- *- * @param {function} callback- *- * @returns {object[]}- */- $.fn.contentChange = function (callback) {- var elements = $(this);-- elements.each(function () {- var element = $(this);-- element.data("lastContents", element.html());-- window.watchContentChange = window.watchContentChange ?- window.watchContentChange :- [];-- window.watchContentChange.push({- "element" : element,- "callback": callback- });- });-- return elements;- };-- setInterval(function() {- if ( window.watchContentChange ) {- for ( var i in window.watchContentChange ) {- if ( window.watchContentChange[ i ].element.data( 'lastContents' ) !== window.watchContentChange[ i ].element.html() ) {- window.watchContentChange[ i ].callback.apply( undefined, [ false ] );- window.watchContentChange[ i ].element.data( 'lastContents', window.watchContentChange[ i ].element.html() )- }- }- }- }, 500 );- })(jQuery);+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.2.7 + */ + if ( ! defined( 'ABSPATH' ) ) { + exit; + } +?> +<script type="text/javascript"> + (function ($) { + if ($.fn.contentChange) + return; + + /** + * Content change event listener. + * + * @url http://stackoverflow.com/questions/3233991/jquery-watch-div/3234646#3234646 + * + * @param {function} callback + * + * @returns {object[]} + */ + $.fn.contentChange = function (callback) { + var elements = $(this); + + elements.each(function () { + var element = $(this); + + element.data("lastContents", element.html()); + + window.watchContentChange = window.watchContentChange ? + window.watchContentChange : + []; + + window.watchContentChange.push({ + "element" : element, + "callback": callback + }); + }); + + return elements; + }; + + setInterval(function() { + if ( window.watchContentChange ) { + for ( var i in window.watchContentChange ) { + if ( window.watchContentChange[ i ].element.data( 'lastContents' ) !== window.watchContentChange[ i ].element.html() ) { + window.watchContentChange[ i ].callback.apply( undefined, [ false ] ); + window.watchContentChange[ i ].element.data( 'lastContents', window.watchContentChange[ i ].element.html() ) + } + } + } + }, 500 ); + })(jQuery); </script>\ No newline at end of file
Vulnerability Existed: no Explanation: This diff shows only line ending changes (CRLF to LF conversion) with no actual code modifications. The file content remains functionally identical between versions 1.2.11 and 1.2.12. No security fixes or new vulnerabilities are introduced by this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/js/open-license-activation.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/js/open-license-activation.php 2026-01-19 00:17:37.679046768 +0000@@ -1,37 +1,37 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 2.0.0- */- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- $license_id = $VARS['license_id'];-?>-<script type="text/javascript">- (function ($) {- var prepareLicenseActivationDialog = function () {- var $dialog = $('.fs-modal-license-activation');-- // Trigger the license activation dialog box.- $($('.activate-license-trigger')[0]).click();--// setTimeout(function(){- $dialog.find('select.fs-licenses option[data-id=<?php echo $license_id ?>]')- .prop('selected', true)- .change();-// }, 100);-- };- if ($('.fs-modal-license-activation').length > 0) {- prepareLicenseActivationDialog();- } else {- $('body').on('licenseActivationLoaded', function () {- prepareLicenseActivationDialog();- });- }- })(jQuery);+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 2.0.0 + */ + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + $license_id = $VARS['license_id']; +?> +<script type="text/javascript"> + (function ($) { + var prepareLicenseActivationDialog = function () { + var $dialog = $('.fs-modal-license-activation'); + + // Trigger the license activation dialog box. + $($('.activate-license-trigger')[0]).click(); + +// setTimeout(function(){ + $dialog.find('select.fs-licenses option[data-id=<?php echo $license_id ?>]') + .prop('selected', true) + .change(); +// }, 100); + + }; + if ($('.fs-modal-license-activation').length > 0) { + prepareLicenseActivationDialog(); + } else { + $('body').on('licenseActivationLoaded', function () { + prepareLicenseActivationDialog(); + }); + } + })(jQuery); </script>\ No newline at end of file
Vulnerability Existed: yes
FALSE POSITIVE
Cross-Site Scripting (XSS) - CWE-79 - inc/freemius/templates/js/open-license-activation.php - Line 24
Old Code:
```php
$dialog.find('select.fs-licenses option[data-id=<?php echo $license_id ?>]')
```
Fixed Code:
```php
$dialog.find('select.fs-licenses option[data-id=<?php echo $license_id ?>]')
```
Explanation:
The diff shows only whitespace/line ending changes (CRLF to LF conversion), not actual code modifications. However, the underlying vulnerability **does exist and persists unfixed**: The `$license_id` variable is directly echoed into a JavaScript attribute context without any escaping or sanitization. This allows an attacker to inject arbitrary JavaScript code if `$license_id` contains malicious input (e.g., `" onclick="alert(document.cookie)"`). The vulnerable code should use `esc_attr()` or `esc_js()` to properly escape the output: `<?php echo esc_attr( $license_id ); ?>`. Since the diff contains no actual code changes, this vulnerability remains unaddressed in version 1.2.12.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/js/style-premium-theme.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/js/style-premium-theme.php 2026-01-19 00:17:37.679046768 +0000@@ -1,53 +1,53 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.2.7- *- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );-- $slug = $fs->get_slug();--?>-<script type="text/javascript">- (function ($) {- // Select the premium theme version.- var $theme = $('#<?php echo $slug ?>-premium-name').parents('.theme'),- addPremiumMetadata = function (firstCall) {- if (!firstCall) {- // Seems like the original theme element is removed from the DOM,- // so we need to reselect the updated one.- $theme = $('#<?php echo $slug ?>-premium-name').parents('.theme');- }-- if (0 === $theme.find('.fs-premium-theme-badge-container').length) {- $theme.addClass('fs-premium');-- var $themeBadgeContainer = $( '<div class="fs-premium-theme-badge-container"></div>' );-- $themeBadgeContainer.append( '<div class="fs-badge fs-premium-theme-badge">' + <?php echo json_encode( $fs->get_text_inline( 'Premium', 'premium' ) ) ?> + '</div>' );-- <?php if ( $fs->is_beta() ) : ?>- $themeBadgeContainer.append( '<div class="fs-badge fs-beta-theme-badge">' + <?php echo json_encode( $fs->get_text_inline( 'Beta', 'beta' ) ) ?> + '</div>' );- <?php endif ?>-- $theme.append( $themeBadgeContainer );- }- };-- addPremiumMetadata(true);-- $theme.contentChange(addPremiumMetadata);- })(jQuery);+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.2.7 + * + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + + $slug = $fs->get_slug(); + +?> +<script type="text/javascript"> + (function ($) { + // Select the premium theme version. + var $theme = $('#<?php echo $slug ?>-premium-name').parents('.theme'), + addPremiumMetadata = function (firstCall) { + if (!firstCall) { + // Seems like the original theme element is removed from the DOM, + // so we need to reselect the updated one. + $theme = $('#<?php echo $slug ?>-premium-name').parents('.theme'); + } + + if (0 === $theme.find('.fs-premium-theme-badge-container').length) { + $theme.addClass('fs-premium'); + + var $themeBadgeContainer = $( '<div class="fs-premium-theme-badge-container"></div>' ); + + $themeBadgeContainer.append( '<div class="fs-badge fs-premium-theme-badge">' + <?php echo json_encode( $fs->get_text_inline( 'Premium', 'premium' ) ) ?> + '</div>' ); + + <?php if ( $fs->is_beta() ) : ?> + $themeBadgeContainer.append( '<div class="fs-badge fs-beta-theme-badge">' + <?php echo json_encode( $fs->get_text_inline( 'Beta', 'beta' ) ) ?> + '</div>' ); + <?php endif ?> + + $theme.append( $themeBadgeContainer ); + } + }; + + addPremiumMetadata(true); + + $theme.contentChange(addPremiumMetadata); + })(jQuery); </script>\ No newline at end of file
Vulnerability Existed: no
Explanation:
This diff contains only whitespace and line ending changes (converting from Unix LF to Windows CRLF line endings, or vice versa). There are no functional code changes between the two versions. The security-relevant code patterns remain identical:
- Line 21: `$slug` is properly obtained from `$fs->get_slug()`
- Line 26: While `$slug` is echoed directly into a jQuery selector context (`$('#<?php echo $slug ?>-premium-name')`), this is not a direct HTML/JavaScript injection vulnerability since it's used within a jQuery selector string where special characters would be escaped or treated literally
- Lines 39-40: The `json_encode()` function is properly used to safely encode strings before insertion into JavaScript
- Lines 42-43: Same proper use of `json_encode()` for safe output
No security fixes were applied in this diff, as no vulnerabilities were present in the original code.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/partials/index.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/partials/index.php 2026-01-19 00:17:37.679046768 +0000@@ -1,2 +1,2 @@-<?php-//Silence is golden+<?php +//Silence is golden
I'll analyze the provided code diff for security fixes. **Analysis Results:** Vulnerability Existed: no No vulnerabilities detected in this diff. **Explanation:** This diff shows only whitespace/formatting changes to the file `inc/freemius/templates/partials/index.php`. The actual code content remains identical: - Line 1: `<?php` (opening PHP tag) - Line 2: `//Silence is golden` (comment) The changes appear to be line ending normalization or trailing whitespace adjustments, which are not security-related. The file itself is an empty index file (a common security practice to prevent directory listing), and no code logic has been modified that could introduce or fix security vulnerabilities.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/partials/network-activation.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/partials/network-activation.php 2026-01-19 00:17:37.679046768 +0000@@ -1,94 +1,94 @@-<?php-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );-- $slug = $fs->get_slug();-- $sites = $VARS['sites'];- $require_license_key = $VARS['require_license_key'];-- $show_delegation_option = $fs->apply_filters( 'show_delegation_option', true );- $enable_per_site_activation = $fs->apply_filters( 'enable_per_site_activation', true );-?>-<?php $separator = '<td>|</td>' ?>-<div class="fs-multisite-options-container fs-apply-on-all-sites"<?php if ( ! $enable_per_site_activation )- echo ' style="display: none;"' ?>>- <table class="fs-all-sites-options">- <tbody>- <tr>- <td width="600">- <label>- <?php- if ( ! $fs->is_network_upgrade_mode() ) {- $apply_checkbox_label = $require_license_key ?- fs_text_inline( 'Activate license on all sites in the network.', 'activate-license-on-all-sites-in-the-network', $slug ) :- fs_text_inline( 'Apply on all sites in the network.', 'apply-on-all-sites-in-the-network', $slug );- } else {- $apply_checkbox_label = $require_license_key ?- fs_text_inline( 'Activate license on all pending sites.', 'activate-license-on-pending-sites-in-the-network', $slug ) :- fs_text_inline( 'Apply on all pending sites.', 'apply-on-pending-sites-in-the-network', $slug );-- }- ?>- <input class="fs-apply-on-all-sites-checkbox" type="checkbox" value="true" checked><span><?php echo esc_html( $apply_checkbox_label ) ?></span>- </label>- </td>- <?php if ( ! $require_license_key ) : ?>- <td><a class="action action-allow" data-action-type="allow" href="#"><?php fs_esc_html_echo_inline( 'allow', 'allow', $slug ) ?></a></td>- <?php echo $separator ?>- <?php if ( $show_delegation_option ) : ?>- <td><a class="action action-delegate" data-action-type="delegate" href="#"><?php fs_esc_html_echo_inline( 'delegate', 'delegate', $slug ) ?></a></td>- <?php endif ?>- <?php if ( $fs->is_enable_anonymous() ) : ?>- <?php echo $separator ?>- <td><a class="action action-skip" data-action-type="skip" href="#"><?php echo strtolower( fs_esc_html_inline( 'skip', 'skip', $slug ) ) ?></a></td>- <?php endif ?>- <?php endif ?>- </tr>- </tbody>- </table>- <div class="fs-sites-list-container">- <table cellspacing="0">- <tbody>- <?php $site_props = array('uid', 'url', 'title', 'language') ?>- <?php foreach ( $sites as $site ) : ?>- <tr<?php if ( ! empty( $site['license_id'] ) ) {- echo ' data-license-id="' . esc_attr( $site['license_id'] ) . '"';- } ?>>- <?php if ( $require_license_key ) : ?>- <td><input type="checkbox" value="true" /></td>- <?php endif ?>- <td class="blog-id"><span><?php echo esc_html( $site['blog_id'] ) ?></span>.</td>- <td width="600"><span><?php- $url = str_replace( 'http://', '', str_replace( 'https://', '', $site['url'] ) );- echo esc_html( $url );- ?></span>- <?php foreach ($site_props as $prop) : ?>- <input class="<?php echo esc_attr( $prop ) ?>" type="hidden" value="<?php echo esc_attr($site[$prop]) ?>" />- <?php endforeach ?>- </td>- <?php if ( ! $require_license_key ) : ?>- <td><a class="action action-allow selected" data-action-type="allow" href="#"><?php fs_esc_html_echo_inline( 'allow', 'allow', $slug ) ?></a></td>- <?php echo $separator ?>- <?php if ( $show_delegation_option ) : ?>- <td><a class="action action-delegate" data-action-type="delegate" href="#"><?php fs_esc_html_echo_inline( 'delegate', 'delegate', $slug ) ?></a></td>- <?php endif ?>- <?php if ( $fs->is_enable_anonymous() ) : ?>- <?php echo $separator ?>- <td><a class="action action-skip" data-action-type="skip" href="#"><?php echo strtolower( fs_esc_html_inline( 'skip', 'skip', $slug ) ) ?></a></td>- <?php endif ?>- <?php endif ?>- </tr>- <?php endforeach ?>- </tbody>- </table>- </div>-</div>+<?php + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + + $slug = $fs->get_slug(); + + $sites = $VARS['sites']; + $require_license_key = $VARS['require_license_key']; + + $show_delegation_option = $fs->apply_filters( 'show_delegation_option', true ); + $enable_per_site_activation = $fs->apply_filters( 'enable_per_site_activation', true ); +?> +<?php $separator = '<td>|</td>' ?> +<div class="fs-multisite-options-container fs-apply-on-all-sites"<?php if ( ! $enable_per_site_activation ) + echo ' style="display: none;"' ?>> + <table class="fs-all-sites-options"> + <tbody> + <tr> + <td width="600"> + <label> + <?php + if ( ! $fs->is_network_upgrade_mode() ) { + $apply_checkbox_label = $require_license_key ? + fs_text_inline( 'Activate license on all sites in the network.', 'activate-license-on-all-sites-in-the-network', $slug ) : + fs_text_inline( 'Apply on all sites in the network.', 'apply-on-all-sites-in-the-network', $slug ); + } else { + $apply_checkbox_label = $require_license_key ? + fs_text_inline( 'Activate license on all pending sites.', 'activate-license-on-pending-sites-in-the-network', $slug ) : + fs_text_inline( 'Apply on all pending sites.', 'apply-on-pending-sites-in-the-network', $slug ); + + } + ?> + <input class="fs-apply-on-all-sites-checkbox" type="checkbox" value="true" checked><span><?php echo esc_html( $apply_checkbox_label ) ?></span> + </label> + </td> + <?php if ( ! $require_license_key ) : ?> + <td><a class="action action-allow" data-action-type="allow" href="#"><?php fs_esc_html_echo_inline( 'allow', 'allow', $slug ) ?></a></td> + <?php echo $separator ?> + <?php if ( $show_delegation_option ) : ?> + <td><a class="action action-delegate" data-action-type="delegate" href="#"><?php fs_esc_html_echo_inline( 'delegate', 'delegate', $slug ) ?></a></td> + <?php endif ?> + <?php if ( $fs->is_enable_anonymous() ) : ?> + <?php echo $separator ?> + <td><a class="action action-skip" data-action-type="skip" href="#"><?php echo strtolower( fs_esc_html_inline( 'skip', 'skip', $slug ) ) ?></a></td> + <?php endif ?> + <?php endif ?> + </tr> + </tbody> + </table> + <div class="fs-sites-list-container"> + <table cellspacing="0"> + <tbody> + <?php $site_props = array('uid', 'url', 'title', 'language') ?> + <?php foreach ( $sites as $site ) : ?> + <tr<?php if ( ! empty( $site['license_id'] ) ) { + echo ' data-license-id="' . esc_attr( $site['license_id'] ) . '"'; + } ?>> + <?php if ( $require_license_key ) : ?> + <td><input type="checkbox" value="true" /></td> + <?php endif ?> + <td class="blog-id"><span><?php echo esc_html( $site['blog_id'] ) ?></span>.</td> + <td width="600"><span><?php + $url = str_replace( 'http://', '', str_replace( 'https://', '', $site['url'] ) ); + echo esc_html( $url ); + ?></span> + <?php foreach ($site_props as $prop) : ?> + <input class="<?php echo esc_attr( $prop ) ?>" type="hidden" value="<?php echo esc_attr($site[$prop]) ?>" /> + <?php endforeach ?> + </td> + <?php if ( ! $require_license_key ) : ?> + <td><a class="action action-allow selected" data-action-type="allow" href="#"><?php fs_esc_html_echo_inline( 'allow', 'allow', $slug ) ?></a></td> + <?php echo $separator ?> + <?php if ( $show_delegation_option ) : ?> + <td><a class="action action-delegate" data-action-type="delegate" href="#"><?php fs_esc_html_echo_inline( 'delegate', 'delegate', $slug ) ?></a></td> + <?php endif ?> + <?php if ( $fs->is_enable_anonymous() ) : ?> + <?php echo $separator ?> + <td><a class="action action-skip" data-action-type="skip" href="#"><?php echo strtolower( fs_esc_html_inline( 'skip', 'skip', $slug ) ) ?></a></td> + <?php endif ?> + <?php endif ?> + </tr> + <?php endforeach ?> + </tbody> + </table> + </div> +</div>
Vulnerability Existed: no No Security Vulnerabilities Detected - inc/freemius/templates/partials/network-activation.php Explanation: This diff contains only whitespace/line ending changes (converting from Unix LF to Windows CRLF line endings or similar normalization). The actual code logic remains identical between versions 1.2.11 and 1.2.12. No security fixes or regressions are present because: - All PHP escape functions remain in place (`esc_html()`, `esc_attr()`, `fs_esc_html_echo_inline()`) - All input validation and sanitization patterns are unchanged - No new code vulnerabilities are introduced - No existing vulnerabilities are remediated This is purely a formatting/normalization commit with no functional code changes.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/plugin-icon.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/plugin-icon.php 2026-01-19 00:17:37.679046768 +0000@@ -1,22 +1,22 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.1.4- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- */- $fs = freemius( $VARS['id'] );-- $size = isset( $VARS['size'] ) ? $VARS['size'] : 80;-?>-<div class="fs-plugin-icon">- <img src="<?php echo $fs->get_local_icon_url() ?>" width="<?php echo $size ?>" height="<?php echo $size ?>" />+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.1.4 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + */ + $fs = freemius( $VARS['id'] ); + + $size = isset( $VARS['size'] ) ? $VARS['size'] : 80; +?> +<div class="fs-plugin-icon"> + <img src="<?php echo $fs->get_local_icon_url() ?>" width="<?php echo $size ?>" height="<?php echo $size ?>" /> </div>\ No newline at end of file
Vulnerability Existed: not sure
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') - CWE-79 - inc/freemius/templates/plugin-icon.php - Lines 21-22
Old Code:
```php
<img src="<?php echo $fs->get_local_icon_url() ?>" width="<?php echo $size ?>" height="<?php echo $size ?>" />
```
Fixed Code:
```php
<img src="<?php echo $fs->get_local_icon_url() ?>" width="<?php echo $size ?>" height="<?php echo $size ?>" />
```
Explanation:
The diff only shows line ending changes (CRLF to LF conversion), with no actual code logic modifications. The security concern regarding potential XSS vulnerabilities remains unaddressed:
1. `$fs->get_local_icon_url()` - Not escaped in the `src` attribute. If this method returns user-controlled or unsanitized data, it could be exploited for XSS.
2. `$size` variable - Echoed directly into `width` and `height` attributes without sanitization or escaping. If `$VARS['size']` contains malicious input, it could potentially be exploited (e.g., via attribute injection like `80" onload="alert(1)"`).
Since the diff contains only whitespace/line-ending changes and no actual security fixes were applied, the vulnerability status cannot be definitively confirmed as "fixed" or "not fixed" based on this diff alone. The code pattern suggests potential XSS vulnerabilities that would typically require proper escaping using functions like `esc_attr()` or `esc_url()`.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/plugin-info/description.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/plugin-info/description.php 2026-01-19 00:17:37.679046768 +0000@@ -1,73 +1,73 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.6- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- *- * @var FS_Plugin $plugin- */- $plugin = $VARS['plugin'];-- if ( ! empty( $plugin->info->selling_point_0 ) ||- ! empty( $plugin->info->selling_point_1 ) ||- ! empty( $plugin->info->selling_point_2 )- ) : ?>- <div class="fs-selling-points">- <ul>- <?php for ( $i = 0; $i < 3; $i ++ ) : ?>- <?php if ( ! empty( $plugin->info->{'selling_point_' . $i} ) ) : ?>- <li><i class="dashicons dashicons-yes"></i>-- <h3><?php echo esc_html( $plugin->info->{'selling_point_' . $i} ) ?></h3></li>- <?php endif ?>- <?php endfor ?>- </ul>- </div>- <?php endif ?>- <div>- <?php- echo wp_kses( $plugin->info->description, array(- 'a' => array( 'href' => array(), 'title' => array(), 'target' => array() ),- 'b' => array(),- 'i' => array(),- 'p' => array(),- 'blockquote' => array(),- 'h2' => array(),- 'h3' => array(),- 'ul' => array(),- 'ol' => array(),- 'li' => array()- ) );- ?>- </div>-<?php if ( ! empty( $plugin->info->screenshots ) ) : ?>- <?php $screenshots = $plugin->info->screenshots ?>- <div class="fs-screenshots clearfix">- <h3><?php fs_esc_html_echo_inline( 'Screenshots', 'screenshots', $plugin->slug ) ?></h3>- <ul>- <?php $i = 0;- foreach ( $screenshots as $s => $url ) : ?>- <li class="<?php echo ( 0 === $i % 2 ) ? 'odd' : 'even' ?>">- <style>- #section-description .fs-screenshots <?php echo ".fs-screenshot-{$i}" ?>- {- background-image: url('<?php echo $url ?>');- }- </style>- <a href="<?php echo $url ?>"- title="<?php echo esc_attr( sprintf( fs_text_inline( 'Click to view full-size screenshot %d', 'view-full-size-x', $plugin->slug ), $i ) ) ?>"- class="fs-screenshot-<?php echo $i ?>"></a>- </li>- <?php $i ++; endforeach ?>- </ul>- </div>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.6 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * + * @var FS_Plugin $plugin + */ + $plugin = $VARS['plugin']; + + if ( ! empty( $plugin->info->selling_point_0 ) || + ! empty( $plugin->info->selling_point_1 ) || + ! empty( $plugin->info->selling_point_2 ) + ) : ?> + <div class="fs-selling-points"> + <ul> + <?php for ( $i = 0; $i < 3; $i ++ ) : ?> + <?php if ( ! empty( $plugin->info->{'selling_point_' . $i} ) ) : ?> + <li><i class="dashicons dashicons-yes"></i> + + <h3><?php echo esc_html( $plugin->info->{'selling_point_' . $i} ) ?></h3></li> + <?php endif ?> + <?php endfor ?> + </ul> + </div> + <?php endif ?> + <div> + <?php + echo wp_kses( $plugin->info->description, array( + 'a' => array( 'href' => array(), 'title' => array(), 'target' => array() ), + 'b' => array(), + 'i' => array(), + 'p' => array(), + 'blockquote' => array(), + 'h2' => array(), + 'h3' => array(), + 'ul' => array(), + 'ol' => array(), + 'li' => array() + ) ); + ?> + </div> +<?php if ( ! empty( $plugin->info->screenshots ) ) : ?> + <?php $screenshots = $plugin->info->screenshots ?> + <div class="fs-screenshots clearfix"> + <h3><?php fs_esc_html_echo_inline( 'Screenshots', 'screenshots', $plugin->slug ) ?></h3> + <ul> + <?php $i = 0; + foreach ( $screenshots as $s => $url ) : ?> + <li class="<?php echo ( 0 === $i % 2 ) ? 'odd' : 'even' ?>"> + <style> + #section-description .fs-screenshots <?php echo ".fs-screenshot-{$i}" ?> + { + background-image: url('<?php echo $url ?>'); + } + </style> + <a href="<?php echo $url ?>" + title="<?php echo esc_attr( sprintf( fs_text_inline( 'Click to view full-size screenshot %d', 'view-full-size-x', $plugin->slug ), $i ) ) ?>" + class="fs-screenshot-<?php echo $i ?>"></a> + </li> + <?php $i ++; endforeach ?> + </ul> + </div> <?php endif ?>\ No newline at end of file
Vulnerability Existed: no No CWE Violation - inc/freemius/templates/plugin-info/description.php (all lines) Old Code: Lines 1-73 with mixed line endings (CRLF) Fixed Code: Lines 1-73 with consistent line endings (LF) Explanation: This diff shows only a line ending change from CRLF (Windows-style) to LF (Unix-style). No actual code logic was modified. The security controls that were already in place remain unchanged: - The `wp_kses()` function at line 40 properly sanitizes the description output with an allowlist of safe HTML tags - The `esc_html()` function at line 30 properly escapes the selling point text - The `esc_attr()` function at line 68 properly escapes the title attribute - The URL outputs at lines 64 and 68 are not escaped, but this appears to be from an internal trusted plugin data structure rather than user input The line ending normalization is a code formatting change only, not a security fix or vulnerability introduction.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/plugin-info/features.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/plugin-info/features.php 2026-01-19 00:17:37.679046768 +0000@@ -1,114 +1,114 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.6- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- *- * @var FS_Plugin $plugin- */- $plugin = $VARS['plugin'];-- $plans = $VARS['plans'];-- $features_plan_map = array();- foreach ( $plans as $plan ) {- if (!empty($plan->features) && is_array($plan->features)) {- foreach ( $plan->features as $feature ) {- if ( ! isset( $features_plan_map[ $feature->id ] ) ) {- $features_plan_map[ $feature->id ] = array( 'feature' => $feature, 'plans' => array() );- }-- $features_plan_map[ $feature->id ]['plans'][ $plan->id ] = $feature;- }- }-- // Add support as a feature.- if ( ! empty( $plan->support_email ) ||- ! empty( $plan->support_skype ) ||- ! empty( $plan->support_phone ) ||- true === $plan->is_success_manager- ) {- if ( ! isset( $features_plan_map['support'] ) ) {- $support_feature = new stdClass();- $support_feature->id = 'support';- $support_feature->title = fs_text_inline( 'Support', $plugin->slug );- $features_plan_map[ $support_feature->id ] = array( 'feature' => $support_feature, 'plans' => array() );- } else {- $support_feature = $features_plan_map['support']['feature'];- }-- $features_plan_map[ $support_feature->id ]['plans'][ $plan->id ] = $support_feature;- }- }-- // Add updates as a feature for all plans.- $updates_feature = new stdClass();- $updates_feature->id = 'updates';- $updates_feature->title = fs_text_inline( 'Unlimited Updates', 'unlimited-updates', $plugin->slug );- $features_plan_map[ $updates_feature->id ] = array( 'feature' => $updates_feature, 'plans' => array() );- foreach ( $plans as $plan ) {- $features_plan_map[ $updates_feature->id ]['plans'][ $plan->id ] = $updates_feature;- }-?>-<div class="fs-features">- <table>- <thead>- <tr>- <th></th>- <?php foreach ( $plans as $plan ) : ?>- <th>- <?php echo $plan->title ?>- <span class="fs-price"><?php- if ( empty( $plan->pricing ) ) {- fs_esc_html_echo_inline( 'Free', 'free', $plugin->slug );- } else {- foreach ( $plan->pricing as $pricing ) {- /**- * @var FS_Pricing $pricing- */- if ( 1 == $pricing->licenses ) {- if ( $pricing->has_annual() ) {- echo "\${$pricing->annual_price} / " . fs_esc_html_x_inline( 'year', 'as annual period', 'year', $plugin->slug );- } else if ( $pricing->has_monthly() ) {- echo "\${$pricing->monthly_price} / " . fs_esc_html_x_inline( 'mo', 'as monthly period', 'mo', $plugin->slug );- } else {- echo "\${$pricing->lifetime_price}";- }- }- }- }- ?></span>- </th>- <?php endforeach ?>- </tr>- </thead>- <tbody>- <?php $odd = true;- foreach ( $features_plan_map as $feature_id => $data ) : ?>- <tr class="fs-<?php echo $odd ? 'odd' : 'even' ?>">- <td><?php echo esc_html( ucfirst( $data['feature']->title ) ) ?></td>- <?php foreach ( $plans as $plan ) : ?>- <td>- <?php if ( isset( $data['plans'][ $plan->id ] ) ) : ?>- <?php if ( ! empty( $data['plans'][ $plan->id ]->value ) ) : ?>- <b><?php echo esc_html( $data['plans'][ $plan->id ]->value ) ?></b>- <?php else : ?>- <i class="dashicons dashicons-yes"></i>- <?php endif ?>- <?php endif ?>- </td>- <?php endforeach ?>- </tr>- <?php $odd = ! $odd; endforeach ?>- </tbody>- </table>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.6 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * + * @var FS_Plugin $plugin + */ + $plugin = $VARS['plugin']; + + $plans = $VARS['plans']; + + $features_plan_map = array(); + foreach ( $plans as $plan ) { + if (!empty($plan->features) && is_array($plan->features)) { + foreach ( $plan->features as $feature ) { + if ( ! isset( $features_plan_map[ $feature->id ] ) ) { + $features_plan_map[ $feature->id ] = array( 'feature' => $feature, 'plans' => array() ); + } + + $features_plan_map[ $feature->id ]['plans'][ $plan->id ] = $feature; + } + } + + // Add support as a feature. + if ( ! empty( $plan->support_email ) || + ! empty( $plan->support_skype ) || + ! empty( $plan->support_phone ) || + true === $plan->is_success_manager + ) { + if ( ! isset( $features_plan_map['support'] ) ) { + $support_feature = new stdClass(); + $support_feature->id = 'support'; + $support_feature->title = fs_text_inline( 'Support', $plugin->slug ); + $features_plan_map[ $support_feature->id ] = array( 'feature' => $support_feature, 'plans' => array() ); + } else { + $support_feature = $features_plan_map['support']['feature']; + } + + $features_plan_map[ $support_feature->id ]['plans'][ $plan->id ] = $support_feature; + } + } + + // Add updates as a feature for all plans. + $updates_feature = new stdClass(); + $updates_feature->id = 'updates'; + $updates_feature->title = fs_text_inline( 'Unlimited Updates', 'unlimited-updates', $plugin->slug ); + $features_plan_map[ $updates_feature->id ] = array( 'feature' => $updates_feature, 'plans' => array() ); + foreach ( $plans as $plan ) { + $features_plan_map[ $updates_feature->id ]['plans'][ $plan->id ] = $updates_feature; + } +?> +<div class="fs-features"> + <table> + <thead> + <tr> + <th></th> + <?php foreach ( $plans as $plan ) : ?> + <th> + <?php echo $plan->title ?> + <span class="fs-price"><?php + if ( empty( $plan->pricing ) ) { + fs_esc_html_echo_inline( 'Free', 'free', $plugin->slug ); + } else { + foreach ( $plan->pricing as $pricing ) { + /** + * @var FS_Pricing $pricing + */ + if ( 1 == $pricing->licenses ) { + if ( $pricing->has_annual() ) { + echo "\${$pricing->annual_price} / " . fs_esc_html_x_inline( 'year', 'as annual period', 'year', $plugin->slug ); + } else if ( $pricing->has_monthly() ) { + echo "\${$pricing->monthly_price} / " . fs_esc_html_x_inline( 'mo', 'as monthly period', 'mo', $plugin->slug ); + } else { + echo "\${$pricing->lifetime_price}"; + } + } + } + } + ?></span> + </th> + <?php endforeach ?> + </tr> + </thead> + <tbody> + <?php $odd = true; + foreach ( $features_plan_map as $feature_id => $data ) : ?> + <tr class="fs-<?php echo $odd ? 'odd' : 'even' ?>"> + <td><?php echo esc_html( ucfirst( $data['feature']->title ) ) ?></td> + <?php foreach ( $plans as $plan ) : ?> + <td> + <?php if ( isset( $data['plans'][ $plan->id ] ) ) : ?> + <?php if ( ! empty( $data['plans'][ $plan->id ]->value ) ) : ?> + <b><?php echo esc_html( $data['plans'][ $plan->id ]->value ) ?></b> + <?php else : ?> + <i class="dashicons dashicons-yes"></i> + <?php endif ?> + <?php endif ?> + </td> + <?php endforeach ?> + </tr> + <?php $odd = ! $odd; endforeach ?> + </tbody> + </table> </div>\ No newline at end of file
Vulnerability Existed: no Explanation: This diff shows only whitespace and line ending changes (converting from Unix LF to Windows CRLF line endings or vice versa). The actual code logic, functions, and security measures remain completely identical between versions 1.2.11 and 1.2.12. The file contains proper security practices that are preserved: - Line 10: `ABSPATH` constant check prevents direct file execution - Lines 73, 76, 79, 100, 105, 107: Proper use of `esc_html()` function for XSS prevention - Lines 75, 77, 80: Use of `fs_esc_html_echo_inline()` and `fs_esc_html_x_inline()` for escaped output No security vulnerabilities were introduced or fixed in this change—it is purely a file formatting update.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/plugin-info/index.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/plugin-info/index.php 2026-01-19 00:17:37.679046768 +0000@@ -1,3 +1,3 @@-<?php- // Silence is golden.+<?php + // Silence is golden. // Hide file structure from users on unprotected servers.\ No newline at end of file
Vulnerability Existed: no No Vulnerability Identified - inc/freemius/templates/plugin-info/index.php Old Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Fixed Code: ```php <?php // Silence is golden. // Hide file structure from users on unprotected servers. ``` Explanation: This diff contains only whitespace changes (formatting/indentation adjustments). The file remains a blank PHP file with only comments, which is a standard security practice to prevent directory traversal attacks by hiding file structures. No security vulnerabilities are introduced or fixed in this change. The "Silence is golden" comment is a common WordPress convention indicating the file should not output anything when accessed directly.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/plugin-info/screenshots.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/plugin-info/screenshots.php 2026-01-19 00:17:37.679046768 +0000@@ -1,29 +1,29 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.6- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- *- * @var FS_Plugin $plugin- */- $plugin = $VARS['plugin'];-- $screenshots = $VARS['screenshots'];-?>-<ol>- <?php $i = 0;- foreach ( $screenshots as $s => $url ) : ?>- <li>- <a href="<?php echo $url ?>" title="<?php echo esc_attr( sprintf( fs_text_inline( 'Click to view full-size screenshot %d', 'view-full-size-x', $plugin->slug ), $i ) ) ?>"><img src="<?php echo $url ?>"></a>- </li>- <?php $i ++; endforeach ?>-</ol>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.6 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * + * @var FS_Plugin $plugin + */ + $plugin = $VARS['plugin']; + + $screenshots = $VARS['screenshots']; +?> +<ol> + <?php $i = 0; + foreach ( $screenshots as $s => $url ) : ?> + <li> + <a href="<?php echo $url ?>" title="<?php echo esc_attr( sprintf( fs_text_inline( 'Click to view full-size screenshot %d', 'view-full-size-x', $plugin->slug ), $i ) ) ?>"><img src="<?php echo $url ?>"></a> + </li> + <?php $i ++; endforeach ?> +</ol>
Analyzing the provided diff for security vulnerabilities:
---
**Vulnerability Existed:** yes
**Cross-Site Scripting (XSS) - CWE-79 - inc/freemius/templates/plugin-info/screenshots.php - Lines 27-28**
**Old Code:**
```php
<a href="<?php echo $url ?>" title="<?php echo esc_attr( sprintf( fs_text_inline( 'Click to view full-size screenshot %d', 'view-full-size-x', $plugin->slug ), $i ) ) ?>"><img src="<?php echo $url ?>"></a>
```
**Fixed Code:**
```php
<a href="<?php echo $url ?>" title="<?php echo esc_attr( sprintf( fs_text_inline( 'Click to view full-size screenshot %d', 'view-full-size-x', $plugin->slug ), $i ) ) ?>"><img src="<?php echo $url ?>"></a>
```
**Explanation:**
The diff shows only whitespace/line-ending changes (Unix line endings replacing Windows line endings). The actual PHP code remains identical between the two versions. The vulnerability persists in both versions: the `$url` variable is output directly in both the `href` attribute and `src` attribute without proper escaping. While `esc_attr()` is used for the title attribute, it is not applied to the `$url` outputs. If `$url` contains user-controlled or malicious data, this could allow XSS attacks through JavaScript protocol handlers (e.g., `javascript:alert('XSS')`) in the href or src attributes. The fix would require using `esc_url()` to properly sanitize the URL before output.
---
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/powered-by.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/powered-by.php 2026-01-19 00:17:37.679046768 +0000@@ -1,61 +1,61 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.5- */-- /**- * Note for WordPress.org Theme/Plugin reviewer:- * Freemius is an SDK for plugin and theme developers. Since the core- * of the SDK is relevant both for plugins and themes, for obvious reasons,- * we only develop and maintain one code base.- *- * This code will not run for wp.org themes (only plugins)- * since theme admin settings/options are now only allowed in the customizer.- *- * In addition, this page loads an i-frame. We intentionally named it 'frame'- * so it will pass the "Theme Check" that is looking for the string "i" . "frame".- *- * If you have any questions or need clarifications, please don't hesitate- * pinging me on slack, my username is @svovaf.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- $VARS = isset($VARS) ? $VARS : array();-- $fs = freemius( $VARS['module_id'] );-- if ( ! $fs->is_whitelabeled() && ! $fs->apply_filters( 'hide_freemius_powered_by', false ) ) {- wp_enqueue_script( 'jquery' );- wp_enqueue_script( 'json2' );- fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' );- fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );- ?>-<div id="pframe"></div>-<script type="text/javascript">- (function ($) {- $(function () {- var- base_url = '<?php echo WP_FS__ADDRESS ?>',- pframe = $('<i' + 'frame id="fs_promo_tab" src="' + base_url + '/promotional-tab/?<?php echo http_build_query($VARS) ?>#' + encodeURIComponent(document.location.href) + '" height="350" width="60" frameborder="0" style=" background: transparent; position: fixed; top: 20%; right: 0;" scrolling="no"></i' + 'frame>')- .appendTo('#pframe');-- FS.PostMessage.init(base_url);- FS.PostMessage.receive('state', function (state) {- if ('closed' === state)- $('#fs_promo_tab').css('width', '60px');- else- $('#fs_promo_tab').css('width', '345px');- });- });- })(jQuery);-</script>-<?php } ?>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.5 + */ + + /** + * Note for WordPress.org Theme/Plugin reviewer: + * Freemius is an SDK for plugin and theme developers. Since the core + * of the SDK is relevant both for plugins and themes, for obvious reasons, + * we only develop and maintain one code base. + * + * This code will not run for wp.org themes (only plugins) + * since theme admin settings/options are now only allowed in the customizer. + * + * In addition, this page loads an i-frame. We intentionally named it 'frame' + * so it will pass the "Theme Check" that is looking for the string "i" . "frame". + * + * If you have any questions or need clarifications, please don't hesitate + * pinging me on slack, my username is @svovaf. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.2 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + $VARS = isset($VARS) ? $VARS : array(); + + $fs = freemius( $VARS['module_id'] ); + + if ( ! $fs->is_whitelabeled() && ! $fs->apply_filters( 'hide_freemius_powered_by', false ) ) { + wp_enqueue_script( 'jquery' ); + wp_enqueue_script( 'json2' ); + fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' ); + fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' ); + ?> +<div id="pframe"></div> +<script type="text/javascript"> + (function ($) { + $(function () { + var + base_url = '<?php echo WP_FS__ADDRESS ?>', + pframe = $('<i' + 'frame id="fs_promo_tab" src="' + base_url + '/promotional-tab/?<?php echo http_build_query($VARS) ?>#' + encodeURIComponent(document.location.href) + '" height="350" width="60" frameborder="0" style=" background: transparent; position: fixed; top: 20%; right: 0;" scrolling="no"></i' + 'frame>') + .appendTo('#pframe'); + + FS.PostMessage.init(base_url); + FS.PostMessage.receive('state', function (state) { + if ('closed' === state) + $('#fs_promo_tab').css('width', '60px'); + else + $('#fs_promo_tab').css('width', '345px'); + }); + }); + })(jQuery); +</script> +<?php } ?>
Vulnerability Existed: no No Security Vulnerabilities Detected - inc/freemius/templates/powered-by.php Explanation: The diff shows only whitespace/line ending changes between versions 1.2.11 and 1.2.12. All 61 lines of code remain functionally identical. The changes appear to be normalization of line endings (likely CRLF to LF or similar formatting adjustments). While the underlying code does contain potential security concerns (e.g., `http_build_query($VARS)` without explicit escaping, `WP_FS__ADDRESS` output without sanitization), these vulnerabilities existed in version 1.2.11 and were NOT fixed in this diff. Since the request asks for security *fixes* in the diff and no code changes were made, there are no security fixes to report from this version update.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/pricing.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/pricing.php 2026-01-19 00:17:37.679046768 +0000@@ -1,210 +1,210 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.3- */-- /**- * Note for WordPress.org Theme/Plugin reviewer:- * Freemius is an SDK for plugin and theme developers. Since the core- * of the SDK is relevant both for plugins and themes, for obvious reasons,- * we only develop and maintain one code base.- *- * This code (and page) will not run for wp.org themes (only plugins).- *- * In addition, this page loads an i-frame. We intentionally named it 'frame'- * so it will pass the "Theme Check" that is looking for the string "i" . "frame".- *- * UPDATE:- * After ongoing conversations with the WordPress.org TRT we received- * an official approval for including i-frames in the theme's WP Admin setting's- * page tab (the SDK will never add any i-frames on the sitefront). i-frames- * were never against the guidelines, but we wanted to get the team's blessings- * before we move forward. For the record, I got the final approval from- * Ulrich Pogson (@grapplerulrich), a team lead at the TRT during WordCamp- * Europe 2017 (June 16th, 2017).- *- * If you have any questions or need clarifications, please don't hesitate- * pinging me on slack, my username is @svovaf.- *- * @author Vova Feldman (@svovaf)- * @since 1.2.2- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- wp_enqueue_script( 'jquery' );- wp_enqueue_script( 'json2' );- fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' );- fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );- fs_enqueue_local_style( 'fs_common', '/admin/common.css' );-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );- $slug = $fs->get_slug();- $timestamp = time();-- $context_params = array(- 'plugin_id' => $fs->get_id(),- 'plugin_public_key' => $fs->get_public_key(),- 'plugin_version' => $fs->get_plugin_version(),- );-- $bundle_id = $fs->get_bundle_id();- if ( ! is_null( $bundle_id ) ) {- $context_params['bundle_id'] = $bundle_id;- }-- // Get site context secure params.- if ( $fs->is_registered() ) {- $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(- $fs->get_site(),- $timestamp,- 'upgrade'- ) );- } else {- $context_params['home_url'] = home_url();- }-- if ( $fs->is_payments_sandbox() ) // Append plugin secure token for sandbox mode authentication.)- {- $context_params['sandbox'] = FS_Security::instance()->get_secure_token(- $fs->get_plugin(),- $timestamp,- 'checkout'- );- }-- $query_params = array_merge( $context_params, $_GET, array(- 'next' => $fs->_get_sync_license_url( false, false ),- 'plugin_version' => $fs->get_plugin_version(),- // Billing cycle.- 'billing_cycle' => fs_request_get( 'billing_cycle', WP_FS__PERIOD_ANNUALLY ),- 'is_network_admin' => fs_is_network_admin() ? 'true' : 'false',- 'currency' => $fs->apply_filters( 'default_currency', 'usd' ),- 'discounts_model' => $fs->apply_filters( 'pricing/discounts_model', 'absolute' ),- ) );-- $use_external_pricing = $fs->should_use_external_pricing();-- if ( ! $use_external_pricing ) {- $pricing_js_url = fs_asset_url( $fs->get_pricing_js_path() );- wp_enqueue_script( 'freemius-pricing', $pricing_js_url );- } else {- if ( ! $fs->is_registered() ) {- $template_data = array(- 'id' => $fs->get_id(),- );- fs_require_template( 'forms/trial-start.php', $template_data);- }-- $view_params = array(- 'id' => $VARS['id'],- 'page' => strtolower( $fs->get_text_x_inline( 'Pricing', 'noun', 'pricing' ) ),- );- fs_require_once_template('secure-https-header.php', $view_params);- }-- $has_tabs = $fs->_add_tabs_before_content();-- if ( $has_tabs ) {- $query_params['tabs'] = 'true';- }-?>- <div id="fs_pricing" class="wrap fs-section fs-full-size-wrapper">- <?php if ( ! $use_external_pricing ) : ?>- <div id="fs_pricing_wrapper" data-public-url="<?php echo trailingslashit( dirname( $pricing_js_url ) ) ?>"></div>- <?php- $pricing_config = array_merge( array(- 'contact_url' => $fs->contact_url(),- 'is_production' => ( defined( 'WP_FS__IS_PRODUCTION_MODE' ) ? WP_FS__IS_PRODUCTION_MODE : null ),- 'menu_slug' => $fs->get_menu_slug(),- 'mode' => 'dashboard',- 'fs_wp_endpoint_url' => WP_FS__ADDRESS,- 'request_handler_url' => admin_url(- 'admin-ajax.php?' . http_build_query( array(- 'module_id' => $fs->get_id(),- 'action' => $fs->get_ajax_action( 'pricing_ajax_action' ),- 'security' => $fs->get_ajax_security( 'pricing_ajax_action' )- ) )- ),- 'selector' => '#fs_pricing_wrapper',- 'unique_affix' => $fs->get_unique_affix(),- 'show_annual_in_monthly' => $fs->apply_filters( 'pricing/show_annual_in_monthly', true ),- ), $query_params );-- wp_add_inline_script( 'freemius-pricing', 'Freemius.pricing.new( ' . json_encode( $pricing_config ) . ' )' );- ?>- <?php else : ?>- <div id="fs_frame"></div>- <form action="" method="POST">- <input type="hidden" name="user_id"/>- <input type="hidden" name="user_email"/>- <input type="hidden" name="site_id"/>- <input type="hidden" name="public_key"/>- <input type="hidden" name="secret_key"/>- <input type="hidden" name="action" value="account"/>- </form>-- <script type="text/javascript">- (function ($, undef) {- $(function () {- var- // Keep track of the i-frame height.- frame_height = 800,- base_url = '<?php echo WP_FS__ADDRESS ?>',- // Pass the parent page URL into the i-frame in a meaningful way (this URL could be- // passed via query string or hard coded into the child page, it depends on your needs).- src = base_url + '/pricing/?<?php echo http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href),-- // Append the I-frame into the DOM.- frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>')- .appendTo('#fs_frame');-- FS.PostMessage.init(base_url, [frame[0]]);-- FS.PostMessage.receive('height', function (data) {- var h = data.height;- if (!isNaN(h) && h > 0 && h != frame_height) {- frame_height = h;- frame.height(frame_height + 'px');-- FS.PostMessage.postScroll(frame[0]);- }- });-- FS.PostMessage.receive('get_dimensions', function (data) {- FS.PostMessage.post('dimensions', {- height : $(document.body).height(),- scrollTop: $(document).scrollTop()- }, frame[0]);- });-- FS.PostMessage.receive('start_trial', function (data) {- openTrialConfirmationModal(data);- });- });- })(jQuery);- </script>- <?php endif ?>- </div>-<?php- if ( $has_tabs ) {- $fs->_add_tabs_after_content();- }-- $params = array(- 'page' => 'pricing',- 'module_id' => $fs->get_id(),- 'module_type' => $fs->get_module_type(),- 'module_slug' => $slug,- 'module_version' => $fs->get_plugin_version(),- );- fs_require_template( 'powered-by.php', $params );+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.3 + */ + + /** + * Note for WordPress.org Theme/Plugin reviewer: + * Freemius is an SDK for plugin and theme developers. Since the core + * of the SDK is relevant both for plugins and themes, for obvious reasons, + * we only develop and maintain one code base. + * + * This code (and page) will not run for wp.org themes (only plugins). + * + * In addition, this page loads an i-frame. We intentionally named it 'frame' + * so it will pass the "Theme Check" that is looking for the string "i" . "frame". + * + * UPDATE: + * After ongoing conversations with the WordPress.org TRT we received + * an official approval for including i-frames in the theme's WP Admin setting's + * page tab (the SDK will never add any i-frames on the sitefront). i-frames + * were never against the guidelines, but we wanted to get the team's blessings + * before we move forward. For the record, I got the final approval from + * Ulrich Pogson (@grapplerulrich), a team lead at the TRT during WordCamp + * Europe 2017 (June 16th, 2017). + * + * If you have any questions or need clarifications, please don't hesitate + * pinging me on slack, my username is @svovaf. + * + * @author Vova Feldman (@svovaf) + * @since 1.2.2 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + wp_enqueue_script( 'jquery' ); + wp_enqueue_script( 'json2' ); + fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.js' ); + fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' ); + fs_enqueue_local_style( 'fs_common', '/admin/common.css' ); + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + $slug = $fs->get_slug(); + $timestamp = time(); + + $context_params = array( + 'plugin_id' => $fs->get_id(), + 'plugin_public_key' => $fs->get_public_key(), + 'plugin_version' => $fs->get_plugin_version(), + ); + + $bundle_id = $fs->get_bundle_id(); + if ( ! is_null( $bundle_id ) ) { + $context_params['bundle_id'] = $bundle_id; + } + + // Get site context secure params. + if ( $fs->is_registered() ) { + $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params( + $fs->get_site(), + $timestamp, + 'upgrade' + ) ); + } else { + $context_params['home_url'] = home_url(); + } + + if ( $fs->is_payments_sandbox() ) // Append plugin secure token for sandbox mode authentication.) + { + $context_params['sandbox'] = FS_Security::instance()->get_secure_token( + $fs->get_plugin(), + $timestamp, + 'checkout' + ); + } + + $query_params = array_merge( $context_params, $_GET, array( + 'next' => $fs->_get_sync_license_url( false, false ), + 'plugin_version' => $fs->get_plugin_version(), + // Billing cycle. + 'billing_cycle' => fs_request_get( 'billing_cycle', WP_FS__PERIOD_ANNUALLY ), + 'is_network_admin' => fs_is_network_admin() ? 'true' : 'false', + 'currency' => $fs->apply_filters( 'default_currency', 'usd' ), + 'discounts_model' => $fs->apply_filters( 'pricing/discounts_model', 'absolute' ), + ) ); + + $use_external_pricing = $fs->should_use_external_pricing(); + + if ( ! $use_external_pricing ) { + $pricing_js_url = fs_asset_url( $fs->get_pricing_js_path() ); + wp_enqueue_script( 'freemius-pricing', $pricing_js_url ); + } else { + if ( ! $fs->is_registered() ) { + $template_data = array( + 'id' => $fs->get_id(), + ); + fs_require_template( 'forms/trial-start.php', $template_data); + } + + $view_params = array( + 'id' => $VARS['id'], + 'page' => strtolower( $fs->get_text_x_inline( 'Pricing', 'noun', 'pricing' ) ), + ); + fs_require_once_template('secure-https-header.php', $view_params); + } + + $has_tabs = $fs->_add_tabs_before_content(); + + if ( $has_tabs ) { + $query_params['tabs'] = 'true'; + } +?> + <div id="fs_pricing" class="wrap fs-section fs-full-size-wrapper"> + <?php if ( ! $use_external_pricing ) : ?> + <div id="fs_pricing_wrapper" data-public-url="<?php echo trailingslashit( dirname( $pricing_js_url ) ) ?>"></div> + <?php + $pricing_config = array_merge( array( + 'contact_url' => $fs->contact_url(), + 'is_production' => ( defined( 'WP_FS__IS_PRODUCTION_MODE' ) ? WP_FS__IS_PRODUCTION_MODE : null ), + 'menu_slug' => $fs->get_menu_slug(), + 'mode' => 'dashboard', + 'fs_wp_endpoint_url' => WP_FS__ADDRESS, + 'request_handler_url' => admin_url( + 'admin-ajax.php?' . http_build_query( array( + 'module_id' => $fs->get_id(), + 'action' => $fs->get_ajax_action( 'pricing_ajax_action' ), + 'security' => $fs->get_ajax_security( 'pricing_ajax_action' ) + ) ) + ), + 'selector' => '#fs_pricing_wrapper', + 'unique_affix' => $fs->get_unique_affix(), + 'show_annual_in_monthly' => $fs->apply_filters( 'pricing/show_annual_in_monthly', true ), + ), $query_params ); + + wp_add_inline_script( 'freemius-pricing', 'Freemius.pricing.new( ' . json_encode( $pricing_config ) . ' )' ); + ?> + <?php else : ?> + <div id="fs_frame"></div> + <form action="" method="POST"> + <input type="hidden" name="user_id"/> + <input type="hidden" name="user_email"/> + <input type="hidden" name="site_id"/> + <input type="hidden" name="public_key"/> + <input type="hidden" name="secret_key"/> + <input type="hidden" name="action" value="account"/> + </form> + + <script type="text/javascript"> + (function ($, undef) { + $(function () { + var + // Keep track of the i-frame height. + frame_height = 800, + base_url = '<?php echo WP_FS__ADDRESS ?>', + // Pass the parent page URL into the i-frame in a meaningful way (this URL could be + // passed via query string or hard coded into the child page, it depends on your needs). + src = base_url + '/pricing/?<?php echo http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href), + + // Append the I-frame into the DOM. + frame = $('<i' + 'frame " src="' + src + '" width="100%" height="' + frame_height + 'px" scrolling="no" frameborder="0" style="background: transparent; width: 1px; min-width: 100%;"><\/i' + 'frame>') + .appendTo('#fs_frame'); + + FS.PostMessage.init(base_url, [frame[0]]); + + FS.PostMessage.receive('height', function (data) { + var h = data.height; + if (!isNaN(h) && h > 0 && h != frame_height) { + frame_height = h; + frame.height(frame_height + 'px'); + + FS.PostMessage.postScroll(frame[0]); + } + }); + + FS.PostMessage.receive('get_dimensions', function (data) { + FS.PostMessage.post('dimensions', { + height : $(document.body).height(), + scrollTop: $(document).scrollTop() + }, frame[0]); + }); + + FS.PostMessage.receive('start_trial', function (data) { + openTrialConfirmationModal(data); + }); + }); + })(jQuery); + </script> + <?php endif ?> + </div> +<?php + if ( $has_tabs ) { + $fs->_add_tabs_after_content(); + } + + $params = array( + 'page' => 'pricing', + 'module_id' => $fs->get_id(), + 'module_type' => $fs->get_module_type(), + 'module_slug' => $slug, + 'module_version' => $fs->get_plugin_version(), + ); + fs_require_template( 'powered-by.php', $params );
Vulnerability Existed: no Explanation: This diff shows only whitespace/line ending changes (converting line endings, likely from CRLF to LF or similar). No actual code logic has been modified. All PHP statements, function calls, variable assignments, security functions, and data handling remain identical between versions 1.2.11 and 1.2.12. The file contains several security-relevant operations (use of `$_GET`, `http_build_query()`, `json_encode()`, iframe handling), but none of these have been altered in this update. Therefore, no security vulnerabilities have been introduced or fixed by this diff.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/secure-https-header.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/secure-https-header.php 2026-01-19 00:17:37.679046768 +0000@@ -1,39 +1,39 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.1.8- *- * @var array $VARS- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-?>-<div class="fs-secure-notice">- <i class="dashicons dashicons-lock"></i>- <span><?php- if ( ! empty( $VARS['message'] ) ) {- echo esc_html( $VARS['message'] );- } else {- /**- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );-- echo esc_html( sprintf(- /* translators: %s: Page name */- $fs->get_text_inline( 'Secure HTTPS %s page, running from an external domain', 'secure-x-page-header' ),- $VARS['page']- ) ) .- ' - ' .- sprintf(- '<a class="fs-security-proof" href="%s" target="_blank" rel="noopener">%s</a>',- 'https://www.mcafeesecure.com/verify?host=' . WP_FS__ROOT_DOMAIN_PRODUCTION,- 'Freemius Inc. [US]'- );- }- ?></span>+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.1.8 + * + * @var array $VARS + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } +?> +<div class="fs-secure-notice"> + <i class="dashicons dashicons-lock"></i> + <span><?php + if ( ! empty( $VARS['message'] ) ) { + echo esc_html( $VARS['message'] ); + } else { + /** + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + + echo esc_html( sprintf( + /* translators: %s: Page name */ + $fs->get_text_inline( 'Secure HTTPS %s page, running from an external domain', 'secure-x-page-header' ), + $VARS['page'] + ) ) . + ' - ' . + sprintf( + '<a class="fs-security-proof" href="%s" target="_blank" rel="noopener">%s</a>', + 'https://www.mcafeesecure.com/verify?host=' . WP_FS__ROOT_DOMAIN_PRODUCTION, + 'Freemius Inc. [US]' + ); + } + ?></span> </div>\ No newline at end of file
Vulnerability Existed: no No CWE - No Security Vulnerability Detected Explanation: This diff shows only formatting changes (line ending conversion from CRLF to LF, likely due to line normalization). The actual code logic remains identical between the two versions. No security vulnerabilities were introduced or fixed. The file contains proper security practices: - Input validation via `esc_html()` for user-controlled `$VARS['message']` - HTTPS-only external link - WordPress security checks with `ABSPATH` definition verification - Proper output escaping in sprintf context The changes are purely cosmetic/formatting and do not affect security posture.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/sticky-admin-notice-js.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/sticky-admin-notice-js.php 2026-01-19 00:17:37.679046768 +0000@@ -1,40 +1,40 @@-<?php- /**- * Sticky admin notices JavaScript handler for dismissing notice messages- * by sending AJAX call to the server in order to remove the message from the Database.- *- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.0.7- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-?>-<script type="text/javascript" >- jQuery( document ).ready(function( $ ) {- $( '.fs-notice.fs-sticky .fs-close' ).click(function() {- var- notice = $( this ).parents( '.fs-notice' ),- id = notice.attr( 'data-id' ),- ajaxActionSuffix = notice.attr( 'data-manager-id' ).replace( ':', '-' );-- notice.fadeOut( 'fast', function() {- var data = {- action : 'fs_dismiss_notice_action_' + ajaxActionSuffix,- // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.- _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_dismiss_notice_action' ) ); ?>,- message_id: id- };-- $.post( <?php echo Freemius::ajax_url() ?>, data, function( response ) {-- });-- notice.remove();- });- });- });-</script>+<?php + /** + * Sticky admin notices JavaScript handler for dismissing notice messages + * by sending AJAX call to the server in order to remove the message from the Database. + * + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.0.7 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } +?> +<script type="text/javascript" > + jQuery( document ).ready(function( $ ) { + $( '.fs-notice.fs-sticky .fs-close' ).click(function() { + var + notice = $( this ).parents( '.fs-notice' ), + id = notice.attr( 'data-id' ), + ajaxActionSuffix = notice.attr( 'data-manager-id' ).replace( ':', '-' ); + + notice.fadeOut( 'fast', function() { + var data = { + action : 'fs_dismiss_notice_action_' + ajaxActionSuffix, + // As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline. + _wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_dismiss_notice_action' ) ); ?>, + message_id: id + }; + + $.post( <?php echo Freemius::ajax_url() ?>, data, function( response ) { + + }); + + notice.remove(); + }); + }); + }); +</script>
Vulnerability Existed: no
No CWE Vulnerability Found - File: inc/freemius/templates/sticky-admin-notice-js.php [Lines 1-40]
Old Code:
```php
<?php
/**
* Sticky admin notices JavaScript handler for dismissing notice messages
* by sending AJAX call to the server in order to remove the message from the Database.
*
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.0.7
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<script type="text/javascript" >
jQuery( document ).ready(function( $ ) {
$( '.fs-notice.fs-sticky .fs-close' ).click(function() {
var
notice = $( this ).parents( '.fs-notice' ),
id = notice.attr( 'data-id' ),
ajaxActionSuffix = notice.attr( 'data-manager-id' ).replace( ':', '-' );
notice.fadeOut( 'fast', function() {
var data = {
action : 'fs_dismiss_notice_action_' + ajaxActionSuffix,
// As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
_wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_dismiss_notice_action' ) ); ?>,
message_id: id
};
$.post( <?php echo Freemius::ajax_url() ?>, data, function( response ) {
});
notice.remove();
});
});
});
</script>
```
Fixed Code:
```php
<?php
/**
* Sticky admin notices JavaScript handler for dismissing notice messages
* by sending AJAX call to the server in order to remove the message from the Database.
*
* @package Freemius
* @copyright Copyright (c) 2015, Freemius, Inc.
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
* @since 1.0.7
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<script type="text/javascript" >
jQuery( document ).ready(function( $ ) {
$( '.fs-notice.fs-sticky .fs-close' ).click(function() {
var
notice = $( this ).parents( '.fs-notice' ),
id = notice.attr( 'data-id' ),
ajaxActionSuffix = notice.attr( 'data-manager-id' ).replace( ':', '-' );
notice.fadeOut( 'fast', function() {
var data = {
action : 'fs_dismiss_notice_action_' + ajaxActionSuffix,
// As such we don't need to use `wp_json_encode` method but using it to follow wp.org guideline.
_wpnonce : <?php echo wp_json_encode( wp_create_nonce( 'fs_dismiss_notice_action' ) ); ?>,
message_id: id
};
$.post( <?php echo Freemius::ajax_url() ?>, data, function( response ) {
});
notice.remove();
});
});
});
</script>
```
Explanation:
This diff contains only whitespace changes (LF line endings converted to CRLF or vice versa). The actual code logic remains identical between versions. No security vulnerabilities were introduced or fixed. The AJAX call properly implements:
- Nonce verification via `wp_create_nonce()` and `wp_json_encode()` for CSRF protection
- Use of WordPress's `Freemius::ajax_url()` for proper action routing
- Data sanitization through WordPress API functions
The code was not vulnerable before and remains secure after this change.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/freemius/templates/tabs-capture-js.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/freemius/templates/tabs-capture-js.php 2026-01-19 00:17:37.679046768 +0000@@ -1,64 +1,64 @@-<?php- /**- * @package Freemius- * @copyright Copyright (c) 2015, Freemius, Inc.- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3- * @since 1.2.2.7- */-- if ( ! defined( 'ABSPATH' ) ) {- exit;- }-- /**- * @var array $VARS- * @var Freemius $fs- */- $fs = freemius( $VARS['id'] );- $slug = $fs->get_slug();-?>-<script type="text/javascript">- (function ($) {- $(document).ready(function () {- var $wrap = $( '.wrap' );- if ( 0 === $wrap.length ) {- $wrap = $( '<div class="wrap">' );- $wrap.insertBefore( $( '#wpbody-content .clear' ) );- }-- $wrap = $wrap.clone().wrap( '<div>' ).parent();-- var- settingHtml = $wrap.html(),- tabsPosition = settingHtml.indexOf('nav-tab-wrapper'),- aboveTabsHtml = '';-- if (-1 < tabsPosition) {- // Find the tabs HTML beginning exact position.- while ('<' !== settingHtml[tabsPosition] && 0 < tabsPosition) {- tabsPosition--;- }-- if (-1 < tabsPosition) {- aboveTabsHtml = settingHtml.substr(0, tabsPosition);-- var tabsHtml = $('.wrap .nav-tab-wrapper').clone().wrap('<div>').parent().html(),- ajaxUrl = <?php echo Freemius::ajax_url() ?>;-- $.ajax({- url : ajaxUrl + (ajaxUrl.includes('?') ? '&' : '?') + $.param({- action : '<?php echo $fs->get_ajax_action( 'store_tabs' ) ?>',- security : '<?php echo $fs->get_ajax_security( 'store_tabs' ) ?>',- module_id: '<?php echo $fs->get_id() ?>'- }),- method : 'POST',- data : aboveTabsHtml + "\n" + tabsHtml + '</div>',- dataType : 'html',- // Avoid escaping the HTML.- processData: false- });- }- }- });- })(jQuery);+<?php + /** + * @package Freemius + * @copyright Copyright (c) 2015, Freemius, Inc. + * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3 + * @since 1.2.2.7 + */ + + if ( ! defined( 'ABSPATH' ) ) { + exit; + } + + /** + * @var array $VARS + * @var Freemius $fs + */ + $fs = freemius( $VARS['id'] ); + $slug = $fs->get_slug(); +?> +<script type="text/javascript"> + (function ($) { + $(document).ready(function () { + var $wrap = $( '.wrap' ); + if ( 0 === $wrap.length ) { + $wrap = $( '<div class="wrap">' ); + $wrap.insertBefore( $( '#wpbody-content .clear' ) ); + } + + $wrap = $wrap.clone().wrap( '<div>' ).parent(); + + var + settingHtml = $wrap.html(), + tabsPosition = settingHtml.indexOf('nav-tab-wrapper'), + aboveTabsHtml = ''; + + if (-1 < tabsPosition) { + // Find the tabs HTML beginning exact position. + while ('<' !== settingHtml[tabsPosition] && 0 < tabsPosition) { + tabsPosition--; + } + + if (-1 < tabsPosition) { + aboveTabsHtml = settingHtml.substr(0, tabsPosition); + + var tabsHtml = $('.wrap .nav-tab-wrapper').clone().wrap('<div>').parent().html(), + ajaxUrl = <?php echo Freemius::ajax_url() ?>; + + $.ajax({ + url : ajaxUrl + (ajaxUrl.includes('?') ? '&' : '?') + $.param({ + action : '<?php echo $fs->get_ajax_action( 'store_tabs' ) ?>', + security : '<?php echo $fs->get_ajax_security( 'store_tabs' ) ?>', + module_id: '<?php echo $fs->get_id() ?>' + }), + method : 'POST', + data : aboveTabsHtml + "\n" + tabsHtml + '</div>', + dataType : 'html', + // Avoid escaping the HTML. + processData: false + }); + } + } + }); + })(jQuery); </script>\ No newline at end of file
Vulnerability Existed: no Explanation: The diff shows only line ending changes (CRLF to LF conversion), with no actual code logic modifications. The file content remains functionally identical between versions 1.2.11 and 1.2.12. No security vulnerabilities were introduced or fixed—this is a formatting/normalization change only.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/inc/setup.php 2026-01-19 00:16:00.469016181 +0000+++ cache/filr-protection_1.2.12/inc/setup.php 2026-01-19 00:17:37.679046768 +0000@@ -1,91 +1,91 @@-<?php--if ( !function_exists( 'filr_fs' ) ) {- // Create a helper function for easy SDK access.- function filr_fs() {- global $filr_fs;- if ( !isset( $filr_fs ) ) {- // Include Freemius SDK.- require_once dirname( __FILE__ ) . '/freemius/start.php';- $filr_fs = fs_dynamic_init( array(- 'id' => '5843',- 'slug' => 'filr-protection',- 'type' => 'plugin',- 'public_key' => 'pk_09421f79b04aa92c18913b15581bf',- 'is_premium' => false,- 'has_addons' => false,- 'has_paid_plans' => true,- 'has_affiliation' => 'selected',- 'menu' => array(- 'slug' => 'edit.php?post_type=filr',- 'contact' => false,- 'support' => false,- ),- 'is_live' => true,- ) );- }- return $filr_fs;- }-- // Init Freemius.- filr_fs();- // Signal that SDK was initiated.- do_action( 'filr_fs_loaded' );-}-/**- * Remove freemius pages.- *- * @param bool $is_visible indicates if visible or not.- * @param int $submenu_id current submenu id.- * @return bool- */-function filr_is_submenu_visible( $is_visible, $submenu_id ) {- return false;-}--filr_fs()->add_filter(- 'is_submenu_visible',- 'filr_is_submenu_visible',- 10,- 2-);-/**- * Add custom icon for Freemius.- *- * @return string- */-function filr_custom_icon() {- return FILR_PATH . '/assets/filr-logo.svg';-}--filr_fs()->add_filter( 'plugin_icon', 'filr_custom_icon' );-/**- * Clean up after uninstallation- *- * @return void- */-function filr_cleanup() {- $options = wp_parse_args( get_option( 'filr_status' ), filr\FILR_Admin::get_defaults( 'filr_status' ) );- if ( 'on' === $options['filr_uninstall_delete'] ) {- delete_option( 'filr_status' );- delete_option( 'filr_shortcode' );- $args = array(- 'post_type' => 'filr',- 'posts_per_page' => -1,- 'fields' => 'ids',- );- // Clean posts and directories.- $files = get_posts( $args );- if ( isset( $files ) && !empty( $files ) ) {- foreach ( $files as $file_id ) {- wp_delete_post( $file_id, true );- }- }- // Clean global directorys and files.- filr\FILR_Filesystem::delete_filr_directory();- filr\FILR_Filesystem::delete_index_file();- filr\FILR_Filesystem::delete_htaccess_file();- }-}-+<?php + +if ( !function_exists( 'filr_fs' ) ) { + // Create a helper function for easy SDK access. + function filr_fs() { + global $filr_fs; + if ( !isset( $filr_fs ) ) { + // Include Freemius SDK. + require_once dirname( __FILE__ ) . '/freemius/start.php'; + $filr_fs = fs_dynamic_init( array( + 'id' => '5843', + 'slug' => 'filr-protection', + 'type' => 'plugin', + 'public_key' => 'pk_09421f79b04aa92c18913b15581bf', + 'is_premium' => false, + 'has_addons' => false, + 'has_paid_plans' => true, + 'has_affiliation' => 'selected', + 'menu' => array( + 'slug' => 'edit.php?post_type=filr', + 'contact' => false, + 'support' => false, + ), + 'is_live' => true, + ) ); + } + return $filr_fs; + } + + // Init Freemius. + filr_fs(); + // Signal that SDK was initiated. + do_action( 'filr_fs_loaded' ); +} +/** + * Remove freemius pages. + * + * @param bool $is_visible indicates if visible or not. + * @param int $submenu_id current submenu id. + * @return bool + */ +function filr_is_submenu_visible( $is_visible, $submenu_id ) { + return false; +} + +filr_fs()->add_filter( + 'is_submenu_visible', + 'filr_is_submenu_visible', + 10, + 2 +); +/** + * Add custom icon for Freemius. + * + * @return string + */ +function filr_custom_icon() { + return FILR_PATH . '/assets/filr-logo.svg'; +} + +filr_fs()->add_filter( 'plugin_icon', 'filr_custom_icon' ); +/** + * Clean up after uninstallation + * + * @return void + */ +function filr_cleanup() { + $options = wp_parse_args( get_option( 'filr_status' ), filr\FILR_Admin::get_defaults( 'filr_status' ) ); + if ( 'on' === $options['filr_uninstall_delete'] ) { + delete_option( 'filr_status' ); + delete_option( 'filr_shortcode' ); + $args = array( + 'post_type' => 'filr', + 'posts_per_page' => -1, + 'fields' => 'ids', + ); + // Clean posts and directories. + $files = get_posts( $args ); + if ( isset( $files ) && !empty( $files ) ) { + foreach ( $files as $file_id ) { + wp_delete_post( $file_id, true ); + } + } + // Clean global directorys and files. + filr\FILR_Filesystem::delete_filr_directory(); + filr\FILR_Filesystem::delete_index_file(); + filr\FILR_Filesystem::delete_htaccess_file(); + } +} + filr_fs()->add_action( 'after_uninstall', 'filr_cleanup' );\ No newline at end of file
Vulnerability Existed: no This diff contains only whitespace changes (line ending conversions from CRLF to LF or similar). No actual code logic has been modified, and therefore no security vulnerabilities have been introduced or fixed. The code structure, logic flow, and all security-relevant operations remain identical: - Freemius SDK initialization with the same configuration - Filter and action hook registrations unchanged - Cleanup function logic identical - No changes to permission checks, input validation, or data handling The diff represents a formatting/normalization update with zero security impact.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/src/class-filr-admin.php 2026-01-19 00:16:00.473016429 +0000+++ cache/filr-protection_1.2.12/src/class-filr-admin.php 2026-01-19 00:17:37.687047265 +0000@@ -1,863 +1,863 @@-<?php--namespace filr;--/**- * Admin Options Class- */-class FILR_Admin {- /**- * Contains instance or null- *- * @var object|null- */- private static $instance = null;-- /**- * Returns instance of FILR_Admin.- *- * @return object- */- public static function get_instance() {- if ( null === self::$instance ) {- self::$instance = new self();- }- return self::$instance;- }-- /**- * Setting up admin fields- *- * @return void- */- public function __construct() {- add_action( 'admin_enqueue_scripts', array($this, 'add_admin_scripts') );- add_action( 'init', array($this, 'register_filr') );- add_action( 'init', array($this, 'register_filr_lists') );- add_action( 'init', array($this, 'setup_settings_page') );- add_filter( 'manage_filr_posts_columns', array($this, 'set_columns') );- add_action(- 'manage_filr_posts_custom_column',- array($this, 'set_columns_content'),- 10,- 2- );- add_filter( 'manage_edit-filr-lists_columns', array($this, 'add_shortcode_column') );- add_filter( 'manage_edit-filr-lists_sortable_columns', array($this, 'add_shortcode_column') );- add_filter(- 'manage_filr-lists_custom_column',- array($this, 'add_shortcode_column_content'),- 10,- 3- );- }-- /**- * Enqueue admin scripts- *- * @return void- */- public function add_admin_scripts() {- $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' );- wp_enqueue_style(- 'filr-admin',- FILR_URL . '/assets/filr-admin' . $suffix . '.css',- array(),- FILR_VERSION,- 'all'- );- wp_enqueue_script(- 'filr-admin',- FILR_URL . '/assets/filr-admin' . $suffix . '.js',- array('jquery'),- FILR_VERSION,- true- );- $file_data = get_post_meta( get_the_id(), 'file-upload', true );- // Media Uploader.- wp_enqueue_media();- // uploader styles and scripts.- wp_enqueue_style(- 'font-fileuploader',- FILR_URL . '/assets/font/font-fileuploader.min.css',- array(),- false,- 'all'- );- wp_enqueue_style(- 'fileuploader',- FILR_URL . '/assets/jquery.fileuploader.min.css',- array(),- false,- 'all'- );- wp_enqueue_script(- 'fileuploader',- FILR_URL . '/assets/jquery.fileuploader.min.js',- array('jquery'),- false,- true- );- if ( !is_null( get_the_id() ) ) {- $settings = wp_parse_args( get_option( 'filr_status' ), self::get_defaults( 'filr_status' ) );- $uploads_directory = wp_upload_dir();- $filr_dir = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . get_the_id() . DIRECTORY_SEPARATOR;- $translations = array(esc_html__( 'Drag and drop files here', 'filr' ), esc_html__( 'or', 'filr' ), __( 'Browse files', 'filr' ));- $post_id = get_the_id();- $user_id = get_current_user_id();- wp_localize_script( 'filr-admin', 'ajax', array(- 'ajax_url' => admin_url( 'admin-ajax.php' ),- 'post_id' => $post_id,- 'file_data' => $file_data,- 'uploader_nonce' => wp_create_nonce( 'filr-upload-file-' . $post_id . '-' . $user_id ),- 'delete_nonce' => wp_create_nonce( 'filr-delete-file-' . $post_id . '-' . $user_id ),- 'filr_dir' => $filr_dir,- 'translations' => $translations,- ) );- }- }-- /**- * Register a custom post type called "filr".- *- * @see get_post_type_labels() for label keys.- */- public function register_filr() {- $labels = array(- 'name' => _x( 'Filr', 'Post type general name', 'filr' ),- 'singular_name' => _x( 'File', 'Post type singular name', 'filr' ),- 'menu_name' => _x( 'Filr', 'Admin Menu text', 'filr' ),- 'name_admin_bar' => _x( 'File', 'Add New on Toolbar', 'filr' ),- 'add_new' => __( 'Add New', 'filr' ),- 'add_new_item' => __( 'Add New File', 'filr' ),- 'new_item' => __( 'New File', 'filr' ),- 'edit_item' => __( 'Edit File', 'filr' ),- 'view_item' => __( 'View File', 'filr' ),- 'all_items' => __( 'All Files', 'filr' ),- 'search_items' => __( 'Search Files', 'filr' ),- 'parent_item_colon' => __( 'Parent Files:', 'filr' ),- 'not_found' => __( 'No Files found.', 'filr' ),- 'not_found_in_trash' => __( 'No Files found in Trash.', 'filr' ),- 'archives' => _x( 'Files archives', 'The post type archive label used in nav menus. Default “Post Archives”. Added in 4.4', 'filr' ),- 'insert_into_item' => _x( 'Insert into File', 'Overrides the “Insert into post”/”Insert into page” phrase (used when inserting media into a post). Added in 4.4', 'filr' ),- 'uploaded_to_this_item' => _x( 'Uploaded to this File', 'Overrides the “Uploaded to this post”/”Uploaded to this page” phrase (used when viewing media attached to a post). Added in 4.4', 'filr' ),- 'filter_items_list' => _x( 'Filter Files list', 'Screen reader text for the filter links heading on the post type listing screen. Default “Filter posts list”/”Filter pages list”. Added in 4.4', 'filr' ),- 'items_list_navigation' => _x( 'File list navigation', 'Screen reader text for the pagination heading on the post type listing screen. Default “Posts list navigation”/”Pages list navigation”. Added in 4.4', 'filr' ),- 'items_list' => _x( 'Files list', 'Screen reader text for the items list heading on the post type listing screen. Default “Posts list”/”Pages list”. Added in 4.4', 'filr' ),- );- $args = array(- 'labels' => $labels,- 'public' => false,- 'publicly_queryable' => false,- 'show_ui' => true,- 'show_in_menu' => true,- 'query_var' => false,- 'capability_type' => 'post',- 'capabilities' => array(- 'edit_post' => apply_filters( 'filr_manage_capability', 'manage_options' ),- 'read_post' => apply_filters( 'filr_manage_capability', 'manage_options' ),- 'delete_post' => apply_filters( 'filr_manage_capability', 'manage_options' ),- 'edit_posts' => apply_filters( 'filr_manage_capability', 'manage_options' ),- 'edit_others_posts' => apply_filters( 'filr_manage_capability', 'manage_options' ),- 'delete_posts' => apply_filters( 'filr_manage_capability', 'manage_options' ),- 'publish_posts' => apply_filters( 'filr_manage_capability', 'manage_options' ),- 'read_private_posts' => apply_filters( 'filr_manage_capability', 'manage_options' ),- ),- 'has_archive' => false,- 'hierarchical' => false,- 'menu_position' => 20,- 'supports' => array('title'),- 'menu_icon' => 'dashicons-download',- );- register_post_type( 'filr', $args );- }-- /**- * Register a 'Lists' taxonomy for post type 'filr'.- *- * @see register_post_type() for registering post types.- */- public function register_filr_lists() {- $labels = array(- 'name' => _x( 'Libraries', 'taxonomy general name', 'filr' ),- 'singular_name' => _x( 'Library', 'taxonomy singular name', 'filr' ),- 'search_items' => __( 'Search Libraries', 'filr' ),- 'popular_items' => __( 'Popular Libraries', 'filr' ),- 'all_items' => __( 'All Libraries', 'filr' ),- 'parent_item' => null,- 'parent_item_colon' => null,- 'edit_item' => __( 'Edit Library', 'filr' ),- 'update_item' => __( 'Update Library', 'filr' ),- 'add_new_item' => __( 'Add New Library', 'filr' ),- 'new_item_name' => __( 'New Library Name', 'filr' ),- 'separate_items_with_commas' => __( 'Separate Libraries with commas', 'filr' ),- 'add_or_remove_items' => __( 'Add or remove Libraries', 'filr' ),- 'choose_from_most_used' => __( 'Choose from the most used Libraries', 'filr' ),- 'not_found' => __( 'No Libraries found.', 'filr' ),- 'menu_name' => __( 'Libraries', 'filr' ),- );- $args = array(- 'hierarchical' => true,- 'labels' => $labels,- 'show_ui' => true,- 'show_admin_column' => true,- 'query_var' => false,- 'public' => false,- );- register_taxonomy( 'filr-lists', 'filr', $args );- }-- /**- * Add shortcode to columns for filr-lists.- *- * @param array $new_columns new columns to add.- *- * @return array- */- public function add_shortcode_column( array $new_columns ) : array {- return array(- 'cb' => '<input type="checkbox" />',- 'name' => esc_html__( 'Name', 'filr' ),- 'slug' => esc_html__( 'Slug', 'filr' ),- 'posts' => esc_html__( 'Files', 'filr' ),- 'shortcode' => esc_html__( 'Shortcode', 'filr' ),- );- }-- /**- * Add content to shortcode column.- *- * @param string $value current value.- * @param string $name name of column.- * @param int $id current id.- *- * @return string- */- public function add_shortcode_column_content( string $value, string $name, int $id ) : string {- $term = get_term( $id, 'filr-lists' );- return '<code>[filr library="' . esc_html( $term->slug ) . '"]</code>';- }-- /**- * Set column headers filr post type- *- * @param array $columns array of columns.- *- * @return array- */- public function set_columns( array $columns ) : array {- $columns['download_link'] = esc_html__( 'Download-Link', 'filr' );- return $columns;- }-- /**- * Add content to registered columns for filr post type.- *- * @param string $column name of the column.- * @param int $post_id current id.- *- * @return void- */- public function set_columns_content( string $column, int $post_id ) {- switch ( $column ) {- case 'download_link':- $is_folder = get_post_meta( $post_id, 'is-folder', true );- $download_url = get_post_meta( $post_id, 'file-download', true );- $secure_url = FILR_Filesystem::get_secure_url( $post_id );- if ( $secure_url ) {- $download_url = $secure_url;- }- if ( $is_folder ) {- esc_html_e( "Folders don't have a download link", 'filr' );- return;- }- ?>- <span class="filr-download-link">- <code>- <?php - echo esc_html( $download_url );- ?>- </code>- </span>- <?php - break;- case 'is_folder':- $is_folder = get_post_meta( $post_id, 'is-folder', true );- $assigned_folder = get_post_meta( $post_id, 'assigned-folder', true );- ?>- <span>- <?php - if ( $is_folder ) {- ?>- <b><?php - esc_html_e( 'Is a Folder', 'filr' );- ?></b><br>- <?php - }- ?>-- <?php - if ( isset( $assigned_folder ) && !empty( $assigned_folder ) && !is_null( get_post( $assigned_folder ) ) ) {- ?>- <b><?php - esc_html_e( 'Is assigned to:', 'filr' );- ?><b><?php - echo esc_html( get_the_title( $assigned_folder ) );- ?></b>- <?php - }- ?>- </span>- <?php - break;- case 'remaining_donwloads':- $is_folder = get_post_meta( $post_id, 'is-folder', true );- $expire_download = get_post_meta( $post_id, 'expire-download', true );- if ( $is_folder ) {- esc_html_e( "Folders don't have an expiration", 'filr' );- return;- }- if ( empty( $expire_download ) ) {- return;- }- ?>- <?php - if ( $expire_download < 1 ) {- ?>- <span style="color:#a00;"><?php - echo esc_html( $expire_download );- ?></span>- <?php - } else {- ?>- <span><?php - echo esc_html( $expire_download );- ?></span>- <?php - }- ?>-- <?php - break;- case 'expire_date':- $is_folder = get_post_meta( $post_id, 'is-folder', true );- $expire_date = get_post_meta( $post_id, 'expire-date', true );- if ( $is_folder ) {- esc_html_e( "Folders don't have an expiration", 'filr' );- return;- }- if ( empty( $expire_date ) ) {- return;- }- $settings = wp_parse_args( get_option( 'filr_shortcode' ), self::get_defaults( 'filr_shortcode' ) );- $expire_date = date_create( $expire_date );- $today = date_create( 'now' );- ?>-- <?php - if ( $today->getTimestamp() >= $expire_date->getTimestamp() ) {- ?>- <span style="color:#a00;"><?php - echo esc_html( date_format( $expire_date, $settings['filr_date_format'] ) );- ?></span>- <?php - } else {- ?>- <span><?php - echo esc_html( date_format( $expire_date, $settings['filr_date_format'] ) );- ?></span>- <?php - }- ?>- <?php - break;- }- }-- /**- * Setting up admin fields- *- * @return void- */- public static function setup_settings_page() {- $settings = new FILR_Settings();- $mode = wp_parse_args( get_option( 'filr_status' ), self::get_defaults( 'filr_status' ) );- // check if protection files exists.- $uploads_directory = wp_upload_dir();- $directory = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $mode['filr_download_directory'];- $index_file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $mode['filr_download_directory'] . DIRECTORY_SEPARATOR . 'index.php';- $htaccess_file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $mode['filr_download_directory'] . DIRECTORY_SEPARATOR . '.htaccess';- // add/remove files based on protection mode.- switch ( $mode['filr_protection_mode'] ) {- case 'no-protection':- if ( file_exists( $index_file ) ) {- FILR_Filesystem::delete_index_file();- }- if ( file_exists( $htaccess_file ) ) {- FILR_Filesystem::delete_htaccess_file();- }- break;- case 'index':- if ( !file_exists( $index_file ) ) {- FILR_Filesystem::create_index_file();- }- if ( file_exists( $htaccess_file ) ) {- FILR_Filesystem::delete_htaccess_file();- }- break;- case 'htaccess':- if ( file_exists( $index_file ) ) {- FILR_Filesystem::delete_index_file();- }- if ( !file_exists( $htaccess_file ) ) {- FILR_Filesystem::create_htaccess_file();- }- break;- default:- if ( file_exists( $index_file ) ) {- FILR_Filesystem::delete_index_file();- }- if ( file_exists( $htaccess_file ) ) {- FILR_Filesystem::delete_htaccess_file();- }- }- $settings->add_section( array(- 'id' => 'filr_status',- 'title' => esc_html__( 'Status', 'filr' ),- ) );- if ( file_exists( $directory ) ) {- $settings->add_field( 'filr_status', array(- 'id' => 'filr_directory',- 'type' => 'html',- 'name' => __( 'Directory', 'filr' ),- 'desc' => __( 'The directory for your download files <b>exists</b>.', 'filr' ),- ) );- } else {- $settings->add_field( 'filr_status', array(- 'id' => 'filr_directory',- 'type' => 'html',- 'name' => __( 'Directory', 'filr' ),- 'desc' => __( 'The directory for your download files <b>not</b> exists.<br> Please create <b>wp-content/uploads/' . $mode['filr_download_directory'] . '</b>.', 'filr' ),- ) );- }- $settings->add_field( 'filr_status', array(- 'id' => 'filr_download_directory',- 'type' => 'text',- 'name' => __( 'Your downloads directory', 'filr' ),- 'default' => 'filr',- 'premium' => 'premium',- ) );- if ( file_exists( $index_file ) || file_exists( $htaccess_file ) ) {- $settings->add_field( 'filr_status', array(- 'id' => 'filr_protection_status',- 'type' => 'html',- 'name' => __( 'Protection Status', 'filr' ),- 'desc' => __( 'The directory for your download files is <b>protected</b>.', 'filr' ),- ) );- } else {- $settings->add_field( 'filr_status', array(- 'id' => 'filr_protection_status',- 'type' => 'html',- 'name' => __( 'Protection', 'filr' ),- 'desc' => __( 'The directory for your download files is <b>not</b> protected.', 'filr' ),- ) );- }- $settings->add_field( 'filr_status', array(- 'id' => 'filr_protection_mode',- 'type' => 'radio',- 'name' => __( 'Protection Mode', 'filr' ),- 'options' => array(- 'no-protection' => __( 'No Protection' ),- 'index' => 'index.php',- 'htaccess' => '.htaccess',- ),- 'desc' => __( '<p><b>No protection:</b> every file is free to access.</p><p><b>index.php:</b> Create an index.php file on the root of your uploads directory. This will hide the content of your whole download directory.<p><p><b>.htaccess:</b> Prevents people to browse your uploads directory and return a 403 code (Forbidden Access).</p>', 'filr' ),- ) );- $settings->add_field( 'filr_status', array(- 'id' => 'filr_secure_download_links',- 'type' => 'toggle',- 'name' => __( 'Secure download links', 'filr' ),- 'default' => 'off',- 'premium' => 'premium',- ) );- $status_settings = wp_parse_args( get_option( 'filr_status' ), self::get_defaults( 'filr_status' ) );- $sample_url = '<code>' . untrailingslashit( get_bloginfo( 'url' ) ) . '?' . $status_settings['filr_download_directory'] . '=123</code>';- $settings->add_field( 'filr_status', array(- 'id' => 'secure_download_links_documentation',- 'type' => 'documentation',- 'name' => '',- 'desc' => sprintf( __( 'Secure download links hide the actual path to the file and show a short URL with the post ID as a parameter. <br>It checks for all security restrictions like user, date-and download limits. Example: %s ' ), $sample_url ),- ) );- if ( file_exists( $directory ) ) {- $settings->add_field( 'filr_status', array(- 'id' => 'filr_check_directory',- 'type' => 'html',- 'name' => __( 'Check', 'filr' ),- 'desc' => '<a target="_blank" href="' . $uploads_directory['baseurl'] . '/' . $mode['filr_download_directory'] . '">' . __( 'Check directory protection', 'filr' ) . '</a>',- ) );- }- $zip = __( 'Zip extension is deactivated. Please contact your hosting partner to enable it.', 'filr' );- if ( true === extension_loaded( 'zip' ) ) {- $zip = __( 'Zip extension is active.', 'filr' );- }- $libzip = __( 'libzip extension is deactivated. If you want to use password-protected ZIP files, please contact your hosting partner to enable it.', 'filr' );- if ( true === extension_loaded( 'libzip' ) ) {- $libzip = __( 'libzip extension is active.', 'filr' );- }- $settings->add_field( 'filr_status', array(- 'id' => 'filr_check_server',- 'type' => 'documentation',- 'name' => __( 'Server Settings', 'filr' ),- 'desc' => sprintf(- __( 'Your server has the following configurations:<br><br><b>max_file_uploads:</b> %1$s<br><b>max_upload_size:</b> %2$s</br><b>zip:</b> %3$s</br><b>libzip:</b> %4$s<br><b>PHP:</b> You are running on: %5$s', 'filr' ),- ini_get( 'max_file_uploads' ) . ' ' . __( 'files', 'filr' ),- ini_get( 'post_max_size' ),- $zip,- $libzip,- phpversion()- ),- ) );- $settings->add_field( 'filr_status', array(- 'id' => 'filr_uninstall_delete',- 'type' => 'toggle',- 'name' => __( 'Delete all options and files on uninstall', 'filr' ),- 'default' => 'off',- ) );- $settings->add_section( array(- 'id' => 'filr_shortcode',- 'title' => __( 'Libraries', 'filr' ),- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_shortcode_docs',- 'type' => 'documentation',- 'name' => __( 'Documentation', 'filr' ),- 'desc' => __( 'A basic shortcode looks like this: <code>[filr library="my-library"]</code>. You can copy them directly from FILR->Libraries in your admin area. You can also use <code>[filr library="my-library" filter="uploader"]</code> to only show files where the e-mail address of the user matches the restrict-user field in a file.', 'filr' ),- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_shortcode_colors',- 'type' => 'html',- 'name' => '<h3>' . __( 'Colors and Styles', 'filr' ) . '</h3>',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_thead_background',- 'type' => 'color',- 'name' => __( 'Table head background', 'filr' ),- 'default' => '#fafafa',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_thead_font_color',- 'type' => 'color',- 'name' => __( 'Table head font color', 'filr' ),- 'default' => '#000000',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_tr_background',- 'type' => 'color',- 'name' => __( 'Table tr background', 'filr' ),- 'default' => '#FFFFFF',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_tr_even_background',- 'type' => 'color',- 'name' => __( 'Table tr even background', 'filr' ),- 'default' => '#f5f5f5',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_tr_hover_background',- 'type' => 'color',- 'name' => __( 'Table tr hover background', 'filr' ),- 'default' => '#e3e2e2',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_tr_font_color',- 'type' => 'color',- 'name' => __( 'Table tr font color', 'filr' ),- 'default' => '#000000',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_tr_button_background_color',- 'type' => 'color',- 'name' => __( 'Button background', 'filr' ),- 'default' => '#7200e5',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_tr_button_color',- 'type' => 'color',- 'name' => __( 'Button font color', 'filr' ),- 'default' => '#FFFFFF',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_table_border_radius',- 'type' => 'number',- 'name' => __( 'Table border radius', 'filr' ),- 'default' => 5,- 'min' => 0,- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_shortcode_table_rows',- 'type' => 'html',- 'name' => '<h3>' . __( 'Rows & Columns', 'filr' ) . '</h3>',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_default_number_rows',- 'type' => 'number',- 'name' => __( 'The default number of rows to display in a library', 'filr' ),- 'default' => 10,- 'min' => 0,- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_sort_rows_default',- 'type' => 'number',- 'name' => __( 'The number of the default column to sort the table', 'filr' ),- 'default' => 1,- 'min' => 0,- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_sort_rows_default_type',- 'type' => 'select',- 'name' => __( 'choose the sorting mode used by default', 'filr' ),- 'options' => array(- 'asc' => __( 'ASC', 'filr' ),- 'desc' => __( 'DESC', 'filr' ),- ),- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_shortcode_sort_rows',- 'type' => 'text',- 'name' => __( 'Sort your columns', 'filr' ),- 'default' => 'file|size|type|date|download',- 'desc' => __( 'You can use the following rows: <code>file|size|type|date|download</code>.', 'filr' ),- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_hide_name_row',- 'type' => 'toggle',- 'name' => __( 'Deactivate name column', 'filr' ),- 'default' => 'off',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_hide_size_row',- 'type' => 'toggle',- 'name' => __( 'Deactivate file size column', 'filr' ),- 'default' => 'off',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_hide_type_row',- 'type' => 'toggle',- 'name' => __( 'Deactivate type column', 'filr' ),- 'default' => 'off',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_hide_date_row',- 'type' => 'toggle',- 'name' => __( 'Deactivate date column', 'filr' ),- 'default' => 'off',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_show_publish_instead_of_last_modified_date',- 'type' => 'toggle',- 'name' => __( 'Show publish date instead of last modified date', 'filr' ),- 'default' => 'off',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_shortcode_table_folders',- 'type' => 'html',- 'name' => '<h3>' . __( 'Folders', 'filr' ) . '</h3>',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_folders_font_size',- 'type' => 'number',- 'name' => __( 'Font size of folder headline (in px)', 'filr' ),- 'default' => 22,- 'min' => 0,- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_shortcode_table_additional',- 'type' => 'html',- 'name' => '<h3>' . __( 'Additional', 'filr' ) . '</h3>',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_empty_list',- 'type' => 'textarea',- 'name' => __( 'Alternative text when no files available within a library', 'filr' ),- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_rename_download_button',- 'type' => 'text',- 'name' => __( 'Rename Download Button', 'filr' ),- 'desc' => __( 'Normally Filr shows the name of the file in the download button, here you can change that.', 'filr' ),- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_target_blank_external',- 'type' => 'toggle',- 'name' => __( 'Open external files in new tab', 'filr' ),- 'default' => 'off',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_deactivate_search',- 'type' => 'toggle',- 'name' => __( 'Deactivate Search', 'filr' ),- 'default' => 'off',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_deactivate_pagination',- 'type' => 'toggle',- 'name' => __( 'Deactivate Pagination', 'filr' ),- 'default' => 'off',- ) );- $settings->add_field( 'filr_shortcode', array(- 'id' => 'filr_date_format',- 'type' => 'text',- 'name' => __( 'Date format', 'filr' ),- 'default' => 'Y/m/d',- 'desc' => __( 'You have to use a valid PHP date format string.<br> Examples are <code>Y-m-d</code>, <code>d/m/Y</code> or <code>Y-m-d H:i:s</code>' ),- ) );- $settings->add_section( array(- 'id' => 'filr_frontend_uploader',- 'title' => __( 'Frontend Uploader', 'filr' ),- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_docs',- 'type' => 'documentation',- 'name' => __( 'Documentation', 'filr' ),- 'desc' => __( 'This feature is only available in <b>Filr Pro</b>.', 'filr' ),- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_styles',- 'type' => 'html',- 'name' => '<h3>' . __( 'Styles', 'filr' ) . '</h3>',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_headline',- 'type' => 'text',- 'name' => __( 'Modify Headline', 'filr' ),- 'value' => __( 'Drag and drop files here', 'filr' ),- 'premium' => 'premium',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_limiter_text',- 'type' => 'text',- 'name' => __( 'Modify Limiter text', 'filr' ),- 'value' => __( 'or', 'filr' ),- 'premium' => 'premium',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_button_label',- 'type' => 'text',- 'name' => __( 'Modify button label', 'filr' ),- 'value' => __( 'Browse files', 'filr' ),- 'premium' => 'premium',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_additional',- 'type' => 'html',- 'name' => '<h3>' . __( 'Additional', 'filr' ) . '</h3>',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_features',- 'type' => 'html',- 'name' => '<h3>' . __( 'Features', 'filr' ) . '</h3>',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_activate_folders',- 'type' => 'toggle',- 'name' => __( 'Allow folder selection', 'filr' ),- 'default' => 'off',- 'premium' => 'premium',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_activate_libraries',- 'type' => 'toggle',- 'name' => __( 'Allow library selection', 'filr' ),- 'default' => 'off',- 'premium' => 'premium',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_send_notification',- 'type' => 'toggle',- 'name' => __( 'Send notification E-Mail after new file submit', 'filr' ),- 'default' => 'off',- 'premium' => 'premium',- ) );- $settings->add_field( 'filr_frontend_uploader', array(- 'id' => 'filr_frontend_uploader_reload',- 'type' => 'toggle',- 'name' => __( 'Reload after file submit', 'filr' ),- 'default' => 'off',- 'premium' => 'premium',- ) );- }-- /**- * Return default based on option name.- *- * @param string $option_name name of the option.- *- * @return array- */- public static function get_defaults( string $option_name ) : array {- $settings = array();- switch ( $option_name ) {- case 'filr_status':- $settings = array(- 'filr_download_directory' => 'filr',- 'filr_protection_mode' => 'no-protection',- 'filr_uninstall_delete' => 'off',- 'filr_secure_download_links' => 'off',- 'filr_secure_download_links_encryption' => 'off',- );- break;- case 'filr_shortcode':- $settings = array(- 'filr_thead_background' => '#7200e5',- 'filr_thead_font_color' => '#FFFFFF',- 'filr_tr_background' => '#FFFFFF',- 'filr_tr_even_background' => '#f5f5f5',- 'filr_tr_hover_background' => '#e3e2e2',- 'filr_tr_font_color' => '#000000',- 'filr_tr_button_background_color' => '#7200e5',- 'filr_tr_button_color' => '#FFFFFF',- 'filr_open_folder_button_color' => '#7200e5',- 'filr_close_folder_button_color' => '#d93535',- 'filr_table_border_radius' => 5,- 'filr_hide_name_row' => 'off',- 'filr_hide_size_row' => 'off',- 'filr_hide_remaining_row' => 'off',- 'filr_hide_expires_row' => 'off',- 'filr_show_expired_downloads' => 'off',- 'filr_hide_type_row' => 'off',- 'filr_hide_date_row' => 'off',- 'filr_hide_version_row' => 'off',- 'filr_date_format' => 'Y/m/d',- 'filr_empty_list' => '',- 'filr_deactivate_search' => 'off',- 'filr_deactivate_pagination' => 'off',- 'filr_activate_preview' => 'off',- 'filr_sort_rows_default' => 1,- 'filr_sort_rows_default_type' => 'asc',- 'filr_folders_font_size' => 22,- 'filr_target_blank_external' => 'off',- 'filr_default_number_rows' => 10,- 'filr_hide_user_row' => 'off',- 'filr_shortcode_sort_rows' => 'file|size|type|date|download',- );- break;- }- return $settings;- }-- /**- * Save the old directory name and rename the directory.- *- * @param string $new_value new value to update.- * @param string $old_value old value from option.- *- * @return string- */- public function save_old_directory( string $new_value, string $old_value ) : string {- if ( empty( $old_value ) ) {- return $new_value;- }- return $new_value;- }--}+<?php + +namespace filr; + +/** + * Admin Options Class + */ +class FILR_Admin { + /** + * Contains instance or null + * + * @var object|null + */ + private static $instance = null; + + /** + * Returns instance of FILR_Admin. + * + * @return object + */ + public static function get_instance() { + if ( null === self::$instance ) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * Setting up admin fields + * + * @return void + */ + public function __construct() { + add_action( 'admin_enqueue_scripts', array($this, 'add_admin_scripts') ); + add_action( 'init', array($this, 'register_filr') ); + add_action( 'init', array($this, 'register_filr_lists') ); + add_action( 'init', array($this, 'setup_settings_page') ); + add_filter( 'manage_filr_posts_columns', array($this, 'set_columns') ); + add_action( + 'manage_filr_posts_custom_column', + array($this, 'set_columns_content'), + 10, + 2 + ); + add_filter( 'manage_edit-filr-lists_columns', array($this, 'add_shortcode_column') ); + add_filter( 'manage_edit-filr-lists_sortable_columns', array($this, 'add_shortcode_column') ); + add_filter( + 'manage_filr-lists_custom_column', + array($this, 'add_shortcode_column_content'), + 10, + 3 + ); + } + + /** + * Enqueue admin scripts + * + * @return void + */ + public function add_admin_scripts() { + $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ); + wp_enqueue_style( + 'filr-admin', + FILR_URL . '/assets/filr-admin' . $suffix . '.css', + array(), + FILR_VERSION, + 'all' + ); + wp_enqueue_script( + 'filr-admin', + FILR_URL . '/assets/filr-admin' . $suffix . '.js', + array('jquery'), + FILR_VERSION, + true + ); + $file_data = get_post_meta( get_the_id(), 'file-upload', true ); + // Media Uploader. + wp_enqueue_media(); + // uploader styles and scripts. + wp_enqueue_style( + 'font-fileuploader', + FILR_URL . '/assets/font/font-fileuploader.min.css', + array(), + false, + 'all' + ); + wp_enqueue_style( + 'fileuploader', + FILR_URL . '/assets/jquery.fileuploader.min.css', + array(), + false, + 'all' + ); + wp_enqueue_script( + 'fileuploader', + FILR_URL . '/assets/jquery.fileuploader.min.js', + array('jquery'), + false, + true + ); + if ( !is_null( get_the_id() ) ) { + $settings = wp_parse_args( get_option( 'filr_status' ), self::get_defaults( 'filr_status' ) ); + $uploads_directory = wp_upload_dir(); + $filr_dir = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . get_the_id() . DIRECTORY_SEPARATOR; + $translations = array(esc_html__( 'Drag and drop files here', 'filr' ), esc_html__( 'or', 'filr' ), __( 'Browse files', 'filr' )); + $post_id = get_the_id(); + $user_id = get_current_user_id(); + wp_localize_script( 'filr-admin', 'ajax', array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'post_id' => $post_id, + 'file_data' => $file_data, + 'uploader_nonce' => wp_create_nonce( 'filr-upload-file-' . $post_id . '-' . $user_id ), + 'delete_nonce' => wp_create_nonce( 'filr-delete-file-' . $post_id . '-' . $user_id ), + 'filr_dir' => $filr_dir, + 'translations' => $translations, + ) ); + } + } + + /** + * Register a custom post type called "filr". + * + * @see get_post_type_labels() for label keys. + */ + public function register_filr() { + $labels = array( + 'name' => _x( 'Filr', 'Post type general name', 'filr' ), + 'singular_name' => _x( 'File', 'Post type singular name', 'filr' ), + 'menu_name' => _x( 'Filr', 'Admin Menu text', 'filr' ), + 'name_admin_bar' => _x( 'File', 'Add New on Toolbar', 'filr' ), + 'add_new' => __( 'Add New', 'filr' ), + 'add_new_item' => __( 'Add New File', 'filr' ), + 'new_item' => __( 'New File', 'filr' ), + 'edit_item' => __( 'Edit File', 'filr' ),
I'll analyze the provided code diff for security vulnerabilities. Let me examine the changes carefully. Looking at the diff, I can see this is a line-ending change (the entire file appears to have been converted from CRLF to LF line endings, indicated by the `-` and `+` prefixes on every line, with the actual content remaining identical). **Analysis Results:** Vulnerability Existed: **no** **Explanation:** This diff does not contain any security fixes or security-related code changes. The diff shows a mass conversion of line endings throughout the file: - Old version: Unix/Linux line endings (LF) - New version: Unix/Linux line endings (LF) The actual code content is unchanged - every functional line of code is identical between versions. This is purely a formatting/normalization change, likely performed by a code formatter or version control tool. No vulnerabilities existed in the code before this change, and no vulnerabilities are being fixed by this change. The file contains WordPress plugin code with standard WordPress security practices (use of `esc_html()`, `wp_create_nonce()`, sanitization functions), but these were already present and unchanged by this diff. If you have a different diff with actual code changes that you'd like me to analyze for security vulnerabilities, please provide that instead.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/src/class-filr-filesystem.php 2026-01-19 00:16:00.473016429 +0000+++ cache/filr-protection_1.2.12/src/class-filr-filesystem.php 2026-01-19 00:17:37.687047265 +0000@@ -1,611 +1,611 @@-<?php--namespace filr;--/**- * File System Class- */-class FILR_Filesystem {- /**- * Contains instance or null- *- * @var object|null- */- private static $instance = null;-- /**- * Returns instance of FILR_Filesystem.- *- * @return object- */- public static function get_instance() {- if ( null === self::$instance ) {- self::$instance = new self();- }- return self::$instance;- }-- /**- * Constructor for FILR_Meta.- */- public function __construct() {- add_action( 'wp_ajax_upload_file', array($this, 'ajax_upload_file') );- add_action( 'wp_ajax_delete_file', array($this, 'ajax_delete_file') );- }-- /**- * Ajax handler to upload files via FILR_Uploader.- *- * @return void- */- public function ajax_upload_file() {- if ( !wp_doing_ajax() ) {- wp_die( 'Invalid request', 'Security Error', array(- 'response' => 403,- ) );- }- if ( !is_user_logged_in() ) {- wp_die( 'Authentication required', 'Security Error', array(- 'response' => 401,- ) );- }- $file_id = sanitize_text_field( $_POST['post_id'] );- $nonce = sanitize_text_field( $_POST['nonce'] );- $encryption = false;- $nonce_action = 'filr-upload-file-' . $file_id . '-' . get_current_user_id();- if ( !wp_verify_nonce( $nonce, $nonce_action ) ) {- wp_die( 'Invalid nonce', 'Security Error', array(- 'response' => 403,- ) );- }- if ( !current_user_can( 'edit_post', $file_id ) ) {- wp_die( 'Insufficient permissions', 'Security Error', array(- 'response' => 403,- ) );- }- $post = get_post( $file_id );- if ( !$post || 'filr' !== $post->post_type ) {- wp_die( 'Invalid post', 'Security Error', array(- 'response' => 404,- ) );- }- if ( !current_user_can( 'edit_others_posts' ) && get_current_user_id() !== $post->post_author ) {- wp_die( 'Access denied', 'Security Error', array(- 'response' => 403,- ) );- }- if ( !$this->check_rate_limit( 'upload', get_current_user_id() ) ) {- $this->log_security_event(- 'rate_limit_exceeded',- get_current_user_id(),- $file_id,- 'Upload rate limit exceeded'- );- wp_die( 'Rate limit exceeded', 'Security Error', array(- 'response' => 429,- ) );- }- $this->log_security_event(- 'file_upload_attempt',- get_current_user_id(),- $file_id,- 'User attempting to upload file'- );- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- // build the path.- $uploads_directory = wp_upload_dir();- $filr_directory = apply_filters(- 'filr_file_directory',- $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . $file_id . DIRECTORY_SEPARATOR,- $settings['filr_download_directory'],- $file_id- );- // if directory not exists, create one.- if ( !file_exists( $filr_directory ) ) {- wp_mkdir_p( $filr_directory );- }- $uploader_encryption = 'name';- // upload file.- $file = 'file-upload';- $uploader = new FILR_Uploader($file, array(- 'uploadDir' => $filr_directory,- 'title' => $uploader_encryption,- ));- $data = $uploader->upload();- // check for existing files and combine them.- $existing_files = get_post_meta( $file_id, 'file-upload', true );- if ( isset( $existing_files['files'] ) && !empty( $existing_files['files'] ) ) {- foreach ( $existing_files['files'] as $file ) {- $data['files'][] = $file;- }- }- $file_url = '';- if ( isset( $data['files'][0]['name'] ) ) {- $file_url = $uploads_directory['baseurl'] . '/' . $settings['filr_download_directory'] . '/' . $file_id . '/' . $data['files'][0]['name'];- update_post_meta( $file_id, 'file-download', $file_url );- }- // Clean up file upload before saving meta.- $cleaned_files = array();- foreach ( $data['files'] as $file ) {- $file['name'] = sanitize_file_name( $file['name'] );- $file['title'] = sanitize_file_name( $file['title'] );- $file['old_name'] = sanitize_file_name( $file['old_name'] );- $file['old_title'] = sanitize_file_name( $file['old_title'] );- $cleaned_files[] = $file;- }- $data['files'] = $cleaned_files;- // save file array for later usage.- update_post_meta( $file_id, 'file-upload', $data );- // clean file records.- if ( apply_filters( 'filr_auto_clean', false ) ) {- self::file_cleaner( $file_id );- }- $response = array(- 'file-upload' => $data,- );- if ( !empty( $file_url ) ) {- $response = array(- 'file-upload' => $data,- 'download_link' => $file_url,- );- }- print wp_json_encode( $response );- exit;- }-- /**- * Ajax handler to delete files via FILR_Uploader.- *- * @return void- */- public function ajax_delete_file() {- if ( !wp_doing_ajax() ) {- wp_die( 'Invalid request', 'Security Error', array(- 'response' => 403,- ) );- }- if ( !is_user_logged_in() ) {- wp_die( 'Authentication required', 'Security Error', array(- 'response' => 401,- ) );- }- $file_id = sanitize_text_field( $_POST['post_id'] );- $file_name = sanitize_text_field( $_POST['filename'] );- $nonce = sanitize_text_field( $_POST['nonce'] );- $nonce_action = 'filr-delete-file-' . $file_id . '-' . get_current_user_id();- if ( !wp_verify_nonce( $nonce, $nonce_action ) ) {- wp_die( 'Invalid nonce', 'Security Error', array(- 'response' => 403,- ) );- }- if ( !current_user_can( 'edit_post', $file_id ) ) {- wp_die( 'Insufficient permissions', 'Security Error', array(- 'response' => 403,- ) );- }- $post = get_post( $file_id );- if ( !$post || 'filr' !== $post->post_type ) {- wp_die( 'Invalid post', 'Security Error', array(- 'response' => 404,- ) );- }- if ( !current_user_can( 'edit_others_posts' ) && get_current_user_id() !== $post->post_author ) {- wp_die( 'Access denied', 'Security Error', array(- 'response' => 403,- ) );- }- if ( !$this->check_rate_limit( 'delete', get_current_user_id() ) ) {- $this->log_security_event(- 'rate_limit_exceeded',- get_current_user_id(),- $file_id,- 'Delete rate limit exceeded'- );- wp_die( 'Rate limit exceeded', 'Security Error', array(- 'response' => 429,- ) );- }- if ( !$this->validate_file_name( $file_name ) ) {- $this->log_security_event(- 'invalid_filename',- get_current_user_id(),- $file_id,- 'Invalid filename attempted: ' . $file_name- );- wp_die( 'Invalid file name', 'Security Error', array(- 'response' => 400,- ) );- }- $this->log_security_event(- 'file_delete_attempt',- get_current_user_id(),- $file_id,- 'User attempting to delete file: ' . $file_name- );- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- // build the path.- $uploads_directory = wp_upload_dir();- $filr_directory = apply_filters(- 'filr_file_directory',- $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . $file_id . DIRECTORY_SEPARATOR,- $settings['filr_download_directory'],- $file_id- );- $file = $filr_directory . $file_name;- // delete file from file upload array in post meta.- $existing_files = get_post_meta( $file_id, 'file-upload', true );- $new_files = array();- if ( $existing_files['files'] ) {- foreach ( $existing_files['files'] as $file ) {- if ( $file['name'] !== $file_name ) {- $new_files[] = $file;- }- }- }- // Update new array of files in metadata.- $existing_files['files'] = $new_files;- update_post_meta( $file_id, 'file-upload', $existing_files );- // if more than one file we need to regenerate zip too, otherwise update download link meta only.- if ( $existing_files['files'] ) {- $file_url = $uploads_directory['baseurl'] . '/' . $settings['filr_download_directory'] . '/' . $file_id . '/' . $existing_files['files'][0]['name'];- update_post_meta( $file_id, 'file-download', $file_url );- } else {- delete_post_meta( $file_id, 'file-download' );- }- // delete the file from the filesystem.- if ( isset( $file_name ) ) {- $deletable_file = $filr_directory . str_replace( array(DIRECTORY_SEPARATOR, '\\'), '', $file_name );- if ( file_exists( $deletable_file ) ) {- unlink( $deletable_file );- }- }- // clean file records.- if ( apply_filters( 'filr_auto_clean', false ) ) {- self::file_cleaner( $file_id );- }- $response = array(- 'delete' => true,- );- if ( !empty( $file_url ) ) {- $response = array(- 'delete' => true,- 'download_link' => $file_url,- );- }- print wp_json_encode( $response );- exit;- }-- /**- * Handles the creation of a subfolder inside of /uploads/ directory.- *- * @return void- */- public static function create_filr_directory( $directory_name ) {- $uploads_directory = wp_upload_dir();- $filr_directory = apply_filters( 'filr_directory', $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $directory_name, $directory_name );- if ( !file_exists( $filr_directory ) ) {- wp_mkdir_p( $filr_directory );- }- }-- /**- * Delete a subfolder inside of /uploads/ directory.- *- * @return void- */- public static function delete_filr_directory() {- global $wp_filesystem;- if ( !function_exists( 'WP_Filesystem' ) ) {- require_once ABSPATH . 'wp-admin/includes/file.php';- }- if ( is_null( $wp_filesystem ) ) {- WP_Filesystem();- }- $uploads_directory = wp_upload_dir();- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- $filr_directory = apply_filters( 'filr_directory', $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'], $settings['filr_download_directory'] );- if ( file_exists( $filr_directory ) ) {- $wp_filesystem->delete( $filr_directory, true );- }- }-- /**- * Creates an index.php file to prevent direct access via HTTP.- *- * @return void- */- public static function create_index_file() {- global $wp_filesystem;- if ( !function_exists( 'WP_Filesystem' ) ) {- require_once ABSPATH . 'wp-admin/includes/file.php';- }- if ( is_null( $wp_filesystem ) ) {- WP_Filesystem();- }- $uploads_directory = wp_upload_dir();- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- $file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . 'index.php';- $content = '<?php // silence is golden.';- if ( !file_exists( $file ) ) {- $wp_filesystem->put_contents( $file, $content, FS_CHMOD_FILE );- }- }-- /**- * Delete a the index file- *- * @return void- */- public static function delete_index_file() {- global $wp_filesystem;- if ( !function_exists( 'WP_Filesystem' ) ) {- require_once ABSPATH . 'wp-admin/includes/file.php';- }- if ( is_null( $wp_filesystem ) ) {- WP_Filesystem();- }- $uploads_directory = wp_upload_dir();- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- $file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . 'index.php';- if ( file_exists( $file ) ) {- $wp_filesystem->delete( $file, true );- }- }-- /**- * Creates an .htaccess file to prevent direct access via HTTP.- *- * @return void- */- public static function create_htaccess_file() {- global $wp_filesystem;- if ( !function_exists( 'WP_Filesystem' ) ) {- require_once ABSPATH . 'wp-admin/includes/file.php';- }- if ( is_null( $wp_filesystem ) ) {- WP_Filesystem();- }- $uploads_directory = wp_upload_dir();- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- $file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . '/.htaccess';- $content = 'Options All -Indexes';- if ( !file_exists( $file ) ) {- $wp_filesystem->put_contents( $file, $content, FS_CHMOD_FILE );- }- }-- /**- * Delete a the .htaccess file- *- * @return void- */- public static function delete_htaccess_file() {- global $wp_filesystem;- if ( !function_exists( 'WP_Filesystem' ) ) {- require_once ABSPATH . 'wp-admin/includes/file.php';- }- if ( is_null( $wp_filesystem ) ) {- WP_Filesystem();- }- $uploads_directory = wp_upload_dir();- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- $file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . '/.htaccess';- if ( file_exists( $file ) ) {- $wp_filesystem->delete( $file, true );- }- }-- /**- * Returns unit based on byte size.- *- * @param int $bytes number of bytes.- *- * @return string- */- public static function format_byte_sizes( int $bytes ) : string {- if ( $bytes >= 1073741824 ) {- $bytes = number_format( $bytes / 1073741824, 2 ) . ' GB';- } elseif ( $bytes >= 1048576 ) {- $bytes = number_format( $bytes / 1048576, 2 ) . ' MB';- } elseif ( $bytes >= 1024 ) {- $bytes = number_format( $bytes / 1024, 2 ) . ' KB';- } elseif ( $bytes > 1 ) {- $bytes = $bytes . ' bytes';- } elseif ( 1 === $bytes ) {- $bytes = $bytes . ' byte';- } else {- $bytes = '0 bytes';- }- return $bytes;- }-- /**- * Block file access via htaccess- *- * @param int $file_id current download object id.- * @param string $expire_date a date string for expiration.- * @param string $remaining_downloads number of remaining downloads available.- *- * @return bool- */- public static function block_file_access( int $file_id, string $expire_date, string $remaining_downloads ) : bool {- return false;- }-- /**- * Check if files has to be blocked per interval (hourly).- *- * @return void- */- public function check_file_access_on_interval() {- }-- /**- * Clean file records with filesystem comparing.- *- * @param int $file_id current file id.- *- * @return void- */- public static function file_cleaner( int $file_id ) {- $file_upload = get_post_meta( $file_id, 'file-upload', true );- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- $uploads_directory = wp_upload_dir();- $filr_directory = apply_filters(- 'filr_file_directory',- $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . $file_id . DIRECTORY_SEPARATOR,- $settings['filr_download_directory'],- $file_id- );- $remaining_files = list_files( $filr_directory );- $current_files = array();- foreach ( $file_upload['files'] as $file ) {- $current_files[] = $file['file'];- }- foreach ( $remaining_files as $file ) {- if ( !in_array( $file, $current_files, true ) ) {- unlink( $file );- }- }- }-- /**- * Clean file records with filesystem comparing.- *- * @param int $file_id current file id.- *- * @return void- */- public static function check_encryption_mode( int $file_id, $encrypt ) {- }-- /**- * Open file and force download with PHP.- *- * @return void- */- public function open_file() {- }-- /**- * Get secure download URL from id.- *- * @param int $post_id given post id.- *- * @return string|bool- */- public static function get_secure_url( int $post_id ) {- return false;- }-- /**- * Check rate limiting for file operations- *- * @param string $action The action being performed (upload, delete)- * @param int $user_id The user ID- * @return bool True if within rate limit, false otherwise- */- private function check_rate_limit( $action, $user_id ) {- $rate_limit_key = 'filr_rate_limit_' . $action . '_' . $user_id;- $rate_limit_data = get_transient( $rate_limit_key );- $max_operations = 10;- $time_window = 60;- if ( false === $rate_limit_data ) {- set_transient( $rate_limit_key, 1, $time_window );- return true;- }- if ( $rate_limit_data >= $max_operations ) {- return false;- }- set_transient( $rate_limit_key, $rate_limit_data + 1, $time_window );- return true;- }-- /**- * Validate file name to prevent path traversal attacks- *- * @param string $filename The file name to validate- * @return bool True if valid, false otherwise- */- private function validate_file_name( $filename ) {- if ( strpos( $filename, '..' ) !== false ) {- return false;- }- if ( strpos( $filename, '/' ) !== false || strpos( $filename, '\\' ) !== false ) {- return false;- }- if ( strpos( $filename, "\x00" ) !== false ) {- return false;- }- if ( strlen( $filename ) > 255 ) {- return false;- }- $dangerous_chars = array(- '<',- '>',- ':',- '"',- '|',- '?',- '*'- );- foreach ( $dangerous_chars as $char ) {- if ( strpos( $filename, $char ) !== false ) {- return false;- }- }- return true;- }-- /**- * Log security events for audit purposes- *- * @param string $action The action performed- * @param int $user_id The user ID- * @param int $post_id The post ID- * @param string $details Additional details- */- private function log_security_event(- $action,- $user_id,- $post_id,- $details = ''- ) {- $log_entry = array(- 'timestamp' => current_time( 'mysql' ),- 'action' => $action,- 'user_id' => $user_id,- 'post_id' => $post_id,- 'ip_address' => $this->get_client_ip(),- 'details' => $details,- );- $security_logs = get_option( 'filr_security_logs', array() );- $security_logs[] = $log_entry;- if ( count( $security_logs ) > 1000 ) {- $security_logs = array_slice( $security_logs, -1000 );- }- update_option( 'filr_security_logs', $security_logs );- }-- /**- * Get client IP address- *- * @return string The client IP address- */- private function get_client_ip() {- $ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR');- foreach ( $ip_keys as $key ) {- if ( array_key_exists( $key, $_SERVER ) === true ) {- foreach ( explode( ',', $_SERVER[$key] ) as $ip ) {- $ip = trim( $ip );- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {- return $ip;- }- }- }- }- return $_SERVER['REMOTE_ADDR'] ?? 'unknown';- }--}+<?php + +namespace filr; + +/** + * File System Class + */ +class FILR_Filesystem { + /** + * Contains instance or null + * + * @var object|null + */ + private static $instance = null; + + /** + * Returns instance of FILR_Filesystem. + * + * @return object + */ + public static function get_instance() { + if ( null === self::$instance ) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * Constructor for FILR_Meta. + */ + public function __construct() { + add_action( 'wp_ajax_upload_file', array($this, 'ajax_upload_file') ); + add_action( 'wp_ajax_delete_file', array($this, 'ajax_delete_file') ); + } + + /** + * Ajax handler to upload files via FILR_Uploader. + * + * @return void + */ + public function ajax_upload_file() { + if ( !wp_doing_ajax() ) { + wp_die( 'Invalid request', 'Security Error', array( + 'response' => 403, + ) ); + } + if ( !is_user_logged_in() ) { + wp_die( 'Authentication required', 'Security Error', array( + 'response' => 401, + ) ); + } + $file_id = sanitize_text_field( $_POST['post_id'] ); + $nonce = sanitize_text_field( $_POST['nonce'] ); + $encryption = false; + $nonce_action = 'filr-upload-file-' . $file_id . '-' . get_current_user_id(); + if ( !wp_verify_nonce( $nonce, $nonce_action ) ) { + wp_die( 'Invalid nonce', 'Security Error', array( + 'response' => 403, + ) ); + } + if ( !current_user_can( 'edit_post', $file_id ) ) { + wp_die( 'Insufficient permissions', 'Security Error', array( + 'response' => 403, + ) ); + } + $post = get_post( $file_id ); + if ( !$post || 'filr' !== $post->post_type ) { + wp_die( 'Invalid post', 'Security Error', array( + 'response' => 404, + ) ); + } + if ( !current_user_can( 'edit_others_posts' ) && get_current_user_id() !== $post->post_author ) { + wp_die( 'Access denied', 'Security Error', array( + 'response' => 403, + ) ); + } + if ( !$this->check_rate_limit( 'upload', get_current_user_id() ) ) { + $this->log_security_event( + 'rate_limit_exceeded', + get_current_user_id(), + $file_id, + 'Upload rate limit exceeded' + ); + wp_die( 'Rate limit exceeded', 'Security Error', array( + 'response' => 429, + ) ); + } + $this->log_security_event( + 'file_upload_attempt', + get_current_user_id(), + $file_id, + 'User attempting to upload file' + ); + $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) ); + // build the path. + $uploads_directory = wp_upload_dir(); + $filr_directory = apply_filters( + 'filr_file_directory', + $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . $file_id . DIRECTORY_SEPARATOR, + $settings['filr_download_directory'], + $file_id + ); + // if directory not exists, create one. + if ( !file_exists( $filr_directory ) ) { + wp_mkdir_p( $filr_directory ); + } + $uploader_encryption = 'name'; + // upload file. + $file = 'file-upload'; + $uploader = new FILR_Uploader($file, array( + 'uploadDir' => $filr_directory, + 'title' => $uploader_encryption, + )); + $data = $uploader->upload(); + // check for existing files and combine them. + $existing_files = get_post_meta( $file_id, 'file-upload', true ); + if ( isset( $existing_files['files'] ) && !empty( $existing_files['files'] ) ) { + foreach ( $existing_files['files'] as $file ) { + $data['files'][] = $file; + } + } + $file_url = ''; + if ( isset( $data['files'][0]['name'] ) ) { + $file_url = $uploads_directory['baseurl'] . '/' . $settings['filr_download_directory'] . '/' . $file_id . '/' . $data['files'][0]['name']; + update_post_meta( $file_id, 'file-download', $file_url ); + } + // Clean up file upload before saving meta. + $cleaned_files = array(); + foreach ( $data['files'] as $file ) { + $file['name'] = sanitize_file_name( $file['name'] ); + $file['title'] = sanitize_file_name( $file['title'] ); + $file['old_name'] = sanitize_file_name( $file['old_name'] ); + $file['old_title'] = sanitize_file_name( $file['old_title'] ); + $cleaned_files[] = $file; + } + $data['files'] = $cleaned_files; + // save file array for later usage. + update_post_meta( $file_id, 'file-upload', $data ); + // clean file records. + if ( apply_filters( 'filr_auto_clean', false ) ) { + self::file_cleaner( $file_id ); + } + $response = array( + 'file-upload' => $data, + ); + if ( !empty( $file_url ) ) { + $response = array( + 'file-upload' => $data, + 'download_link' => $file_url, + ); + } + print wp_json_encode( $response ); + exit; + } + + /** + * Ajax handler to delete files via FILR_Uploader. + * + * @return void + */ + public function ajax_delete_file() { + if ( !wp_doing_ajax() ) { + wp_die( 'Invalid request', 'Security Error', array( + 'response' => 403, + ) ); + } + if ( !is_user_logged_in() ) { + wp_die( 'Authentication required', 'Security Error', array( + 'response' => 401, + ) ); + } + $file_id = sanitize_text_field( $_POST['post_id'] ); + $file_name = sanitize_text_field( $_POST['filename'] ); + $nonce = sanitize_text_field( $_POST['nonce'] ); + $nonce_action = 'filr-delete-file-' . $file_id . '-' . get_current_user_id(); + if ( !wp_verify_nonce( $nonce, $nonce_action ) ) { + wp_die( 'Invalid nonce', 'Security Error', array( + 'response' => 403, + ) ); + } + if ( !current_user_can( 'edit_post', $file_id ) ) { + wp_die( 'Insufficient permissions', 'Security Error', array( + 'response' => 403, + ) ); + } + $post = get_post( $file_id ); + if ( !$post || 'filr' !== $post->post_type ) { + wp_die( 'Invalid post', 'Security Error', array( + 'response' => 404, + ) ); + } + if ( !current_user_can( 'edit_others_posts' ) && get_current_user_id() !== $post->post_author ) { + wp_die( 'Access denied', 'Security Error', array( + 'response' => 403, + ) ); + } + if ( !$this->check_rate_limit( 'delete', get_current_user_id() ) ) { + $this->log_security_event( + 'rate_limit_exceeded', + get_current_user_id(), + $file_id, + 'Delete rate limit exceeded' + ); + wp_die( 'Rate limit exceeded', 'Security Error', array( + 'response' => 429, + ) ); + } + if ( !$this->validate_file_name( $file_name ) ) { + $this->log_security_event( + 'invalid_filename', + get_current_user_id(), + $file_id, + 'Invalid filename attempted: ' . $file_name + ); + wp_die( 'Invalid file name', 'Security Error', array( + 'response' => 400, + ) ); + } + $this->log_security_event( + 'file_delete_attempt', + get_current_user_id(), + $file_id, + 'User attempting to delete file: ' . $file_name + ); + $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) ); + // build the path. + $uploads_directory = wp_upload_dir(); + $filr_directory = apply_filters( + 'filr_file_directory', + $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . $file_id . DIRECTORY_SEPARATOR, + $settings['filr_download_directory'], + $file_id + ); + $file = $filr_directory . $file_name; + // delete file from file upload array in post meta. + $existing_files = get_post_meta( $file_id, 'file-upload', true ); + $new_files = array(); + if ( $existing_files['files'] ) { + foreach ( $existing_files['files'] as $file ) { + if ( $file['name'] !== $file_name ) { + $new_files[] = $file; + } + } + } + // Update new array of files in metadata. + $existing_files['files'] = $new_files; + update_post_meta( $file_id, 'file-upload', $existing_files ); + // if more than one file we need to regenerate zip too, otherwise update download link meta only. + if ( $existing_files['files'] ) { + $file_url = $uploads_directory['baseurl'] . '/' . $settings['filr_download_directory'] . '/' . $file_id . '/' . $existing_files['files'][0]['name']; + update_post_meta( $file_id, 'file-download', $file_url ); + } else { + delete_post_meta( $file_id, 'file-download' ); + } + // delete the file from the filesystem. + if ( isset( $file_name ) ) { + $deletable_file = $filr_directory . str_replace( array(DIRECTORY_SEPARATOR, '\\'), '', $file_name ); + if ( file_exists( $deletable_file ) ) { + unlink( $deletable_file ); + } + } + // clean file records. + if ( apply_filters( 'filr_auto_clean', false ) ) { + self::file_cleaner( $file_id ); + } + $response = array( + 'delete' => true, + ); + if ( !empty( $file_url ) ) { + $response = array( + 'delete' => true, + 'download_link' => $file_url, + ); + } + print wp_json_encode( $response ); + exit; + } + + /** + * Handles the creation of a subfolder inside of /uploads/ directory. + * + * @return void + */ + public static function create_filr_directory( $directory_name ) { + $uploads_directory = wp_upload_dir(); + $filr_directory = apply_filters( 'filr_directory', $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $directory_name, $directory_name ); + if ( !file_exists( $filr_directory ) ) { + wp_mkdir_p( $filr_directory ); + } + } + + /** + * Delete a subfolder inside of /uploads/ directory. + * + * @return void + */ + public static function delete_filr_directory() { + global $wp_filesystem; + if ( !function_exists( 'WP_Filesystem' ) ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + } + if ( is_null( $wp_filesystem ) ) { + WP_Filesystem(); + } + $uploads_directory = wp_upload_dir(); + $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) ); + $filr_directory = apply_filters( 'filr_directory', $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'], $settings['filr_download_directory'] ); + if ( file_exists( $filr_directory ) ) { + $wp_filesystem->delete( $filr_directory, true ); + } + } + + /** + * Creates an index.php file to prevent direct access via HTTP. + * + * @return void + */ + public static function create_index_file() { + global $wp_filesystem; + if ( !function_exists( 'WP_Filesystem' ) ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + } + if ( is_null( $wp_filesystem ) ) { + WP_Filesystem(); + } + $uploads_directory = wp_upload_dir(); + $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) ); + $file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . 'index.php'; + $content = '<?php // silence is golden.'; + if ( !file_exists( $file ) ) { + $wp_filesystem->put_contents( $file, $content, FS_CHMOD_FILE ); + } + } + + /** + * Delete a the index file + * + * @return void + */ + public static function delete_index_file() { + global $wp_filesystem; + if ( !function_exists( 'WP_Filesystem' ) ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + } + if ( is_null( $wp_filesystem ) ) { + WP_Filesystem(); + } + $uploads_directory = wp_upload_dir(); + $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) ); + $file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . 'index.php'; + if ( file_exists( $file ) ) { + $wp_filesystem->delete( $file, true ); + } + } + + /** + * Creates an .htaccess file to prevent direct access via HTTP. + * + * @return void + */ + public static function create_htaccess_file() { + global $wp_filesystem; + if ( !function_exists( 'WP_Filesystem' ) ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + } + if ( is_null( $wp_filesystem ) ) { + WP_Filesystem(); + } + $uploads_directory = wp_upload_dir(); + $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) ); + $file = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . '/.htaccess'; + $content = 'Options All -Indexes'; + if ( !file_exists( $file ) ) { + $wp_filesystem->put_contents( $file, $content, FS_CHMOD_FILE ); + } + } + + /** + * Delete a the .htaccess file + * + * @return void + */ + public static function delete_htaccess_file() { + global $wp_filesystem; + if ( !function_exists( 'WP_Filesystem' ) ) { + require_once ABSPATH . 'wp-admin/includes/file.php';
Analyzing the provided diff... **Analysis Result:** Vulnerability Existed: no The diff shows only whitespace/line ending changes (converting from Unix LF to DOS CRLF line endings, based on the diff structure). The actual code content is identical between versions 1.2.11 and 1.2.12. **Summary:** No security vulnerabilities were introduced or fixed in this diff. The file maintains the same security measures across both versions: - Nonce verification is present - Permission checks are implemented - Rate limiting is enforced - File name validation prevents path traversal attacks - Security event logging is maintained - User authentication checks are in place The only changes are formatting-related (line ending normalization), which do not affect the security posture of the code.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/src/class-filr-meta.php 2026-01-19 00:16:00.473016429 +0000+++ cache/filr-protection_1.2.12/src/class-filr-meta.php 2026-01-19 00:17:37.687047265 +0000@@ -1,291 +1,291 @@-<?php--namespace filr;--/**- * Admin Meta Class- */-class FILR_Meta {- /**- * Contains instance or null- *- * @var object|null- */- private static $instance = null;-- /**- * Returns instance of FILR_Meta.- *- * @return object- */- public static function get_instance() {- if ( null === self::$instance ) {- self::$instance = new self();- }- return self::$instance;- }-- /**- * Constructor for FILR_Meta.- */- public function __construct() {- add_action( 'add_meta_boxes', array($this, 'add_metaboxes') );- add_action( 'save_post', array($this, 'save_metaboxes') );- add_action( 'before_delete_post', array($this, 'clean_files') );- }-- /**- * Adds the meta box container.- *- * @param string $post_type array of post types.- *- * @return void- */- public function add_metaboxes( string $post_type ) {- add_meta_box(- 'file-download',- esc_html__( 'File Download', 'filr' ),- array($this, 'render_file_download'),- 'filr',- 'normal',- 'high'- );- add_meta_box(- 'file-upload',- esc_html__( 'File Upload', 'filr' ),- array($this, 'render_file_upload'),- 'filr',- 'normal',- 'high'- );- add_meta_box(- 'file-management',- esc_html__( 'File Management', 'filr' ),- array($this, 'render_management_options'),- 'filr',- 'side'- );- add_meta_box(- 'file-advanced',- esc_html__( 'Advanced Options', 'filr' ),- array($this, 'render_advanced_options'),- 'filr',- 'side'- );- add_meta_box(- 'file-user',- esc_html__( 'User Options', 'filr' ),- array($this, 'render_user_options'),- 'filr',- 'side'- );- }-- /**- * Render file download metabox.- *- * @param \WP_POST $post The post object.- */- public function render_file_download( \WP_POST $post ) {- $download_url = get_post_meta( $post->ID, 'file-download', true );- $is_folder = get_post_meta( $post->ID, 'is-folder', true );- $secure_url = FILR_Filesystem::get_secure_url( $post->ID );- if ( $secure_url ) {- $download_url = $secure_url;- }- if ( $is_folder ) {- ?>- <div class="filr-meta">- <p><?php - esc_html_e( "Folders don't have a download link", 'filr' );- ?></p>- </div>- <?php - return;- }- ?>- <?php - if ( $download_url ) {- ?>- <span class="filr-download-link"><code><?php - echo esc_url( $download_url );- ?></code></span>- <?php - } else {- ?>- <span class="filr-download-link"><?php - esc_html_e( 'You have not added any files yet.', 'filr' );- ?></span>- <?php - }- ?>-- <?php - }-- /**- * Render Meta Box content.- *- * @param \WP_POST $post The post object.- */- public function render_file_upload( \WP_POST $post ) {- $is_folder = get_post_meta( $post->ID, 'is-folder', true );- $is_external = get_post_meta( $post->ID, 'is-external', true );- $external_source = get_post_meta( $post->ID, 'external-source', true );- if ( $is_folder ) {- ?>- <div class="filr-meta">- <p><?php - esc_html_e( "Folders don't have an upload option", 'filr' );- ?></p>- </div>- <?php - return;- }- if ( $is_external ) {- ?>- <div class="filr-meta">- <p>- <label for="external-source"><?php - esc_html_e( 'External Source', 'filr' );- ?></label>- <input id="external-source" aria-labelledby="external-source" name="external-source" placeholder="<?php - echo esc_url( get_bloginfo( 'url' ) );- ?>/sample-file.png" type="url" value="<?php - echo esc_url( $external_source );- ?>">- </p>- </div>- <?php - return;- }- ?>- <div class="filr-meta">- <input id="file-upload" aria-label="<?php - esc_html_e( 'File Upload', 'filr' );- ?>" name="file-upload" type="file" data-fileuploader-limit="1">- </div>- <div class="filr-meta filr-admin">- <p><small><?php - esc_html_e( 'With FILR Pro you can upload multiple files and automatically zip them.', 'filr' );- ?></small></p>- </div>- <?php - }-- /**- * Render file management metabox.- *- * @param \WP_POST $post The post object.- */- public function render_management_options( \WP_POST $post ) {- ?>- <div class="filr-meta filr-admin">- <p><small><?php - esc_html_e( 'With FILR Pro you can create folders and attach files to it.', 'filr' );- ?></small></p>- </div>- <?php - }-- /**- * Render file options metabox.- *- * @param \WP_POST $post The post object.- */- public function render_advanced_options( \WP_POST $post ) {- $is_folder = get_post_meta( $post->ID, 'is-folder', true );- if ( $is_folder ) {- ?>- <div class="filr-meta">- <p><?php - esc_html_e( "Folders don't have advanced options", 'filr' );- ?></p>- </div>- <?php - return;- }- ?>- <div class="filr-meta filr-admin">- <p><small><?php - echo esc_html_e( 'With FILR Pro you can activate encryption, expire your files by date or number of downloads.', 'filr' );- ?></small></p>- </div>- <?php - }-- /**- * Render user options metabox.- *- * @param \WP_POST $post The post object.- */- public function render_user_options( \WP_POST $post ) {- ?>- <div class="filr-meta filr-admin">- <p><small><?php - esc_html_e( 'With FILR Pro you can restrict files by user email or user role.', 'filr' );- ?></small></p>- </div>- <?php - }-- /**- * Save the meta when the post is saved.- *- * @param int $post_id The ID of the post being saved.- */- public function save_metaboxes( int $post_id ) : int {- // Check if our nonce is set.- if ( !isset( $_POST['filr_nonce_check_value'] ) ) {- return $post_id;- }- // Verify that the nonce is valid.- if ( !wp_verify_nonce( $_POST['filr_nonce_check_value'], 'filr_nonce_check' ) ) {- return $post_id;- }- // If this is an autosave, our form has not been submitted, so we don't want to do anything.- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {- return $post_id;- }- // Check the user's permissions.- if ( !current_user_can( 'edit_post', $post_id ) ) {- return $post_id;- }- // check if files in upload, otherwise delete download link.- $upload = get_post_meta( $post_id, 'file-upload', true );- if ( isset( $upload ) && !empty( $upload ) ) {- if ( count( $upload['files'] ) < 1 ) {- delete_post_meta( $post_id, 'file-download' );- }- }- return $post_id;- }-- /**- * Clean filesystem when post deleted.- *- * @param int $file_id current post id.- *- * @return void- */- public function clean_files( int $file_id ) {- global $post_type;- if ( 'filr' != $post_type ) {- return;- }- global $wp_filesystem;- if ( !function_exists( 'WP_Filesystem' ) ) {- require_once ABSPATH . 'wp-admin/includes/file.php';- }- if ( is_null( $wp_filesystem ) ) {- WP_Filesystem();- }- $uploads_directory = wp_upload_dir();- $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) );- $file_directory = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . $file_id;- if ( file_exists( $file_directory ) ) {- $wp_filesystem->delete( $file_directory, true );- }- }--}+<?php + +namespace filr; + +/** + * Admin Meta Class + */ +class FILR_Meta { + /** + * Contains instance or null + * + * @var object|null + */ + private static $instance = null; + + /** + * Returns instance of FILR_Meta. + * + * @return object + */ + public static function get_instance() { + if ( null === self::$instance ) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * Constructor for FILR_Meta. + */ + public function __construct() { + add_action( 'add_meta_boxes', array($this, 'add_metaboxes') ); + add_action( 'save_post', array($this, 'save_metaboxes') ); + add_action( 'before_delete_post', array($this, 'clean_files') ); + } + + /** + * Adds the meta box container. + * + * @param string $post_type array of post types. + * + * @return void + */ + public function add_metaboxes( string $post_type ) { + add_meta_box( + 'file-download', + esc_html__( 'File Download', 'filr' ), + array($this, 'render_file_download'), + 'filr', + 'normal', + 'high' + ); + add_meta_box( + 'file-upload', + esc_html__( 'File Upload', 'filr' ), + array($this, 'render_file_upload'), + 'filr', + 'normal', + 'high' + ); + add_meta_box( + 'file-management', + esc_html__( 'File Management', 'filr' ), + array($this, 'render_management_options'), + 'filr', + 'side' + ); + add_meta_box( + 'file-advanced', + esc_html__( 'Advanced Options', 'filr' ), + array($this, 'render_advanced_options'), + 'filr', + 'side' + ); + add_meta_box( + 'file-user', + esc_html__( 'User Options', 'filr' ), + array($this, 'render_user_options'), + 'filr', + 'side' + ); + } + + /** + * Render file download metabox. + * + * @param \WP_POST $post The post object. + */ + public function render_file_download( \WP_POST $post ) { + $download_url = get_post_meta( $post->ID, 'file-download', true ); + $is_folder = get_post_meta( $post->ID, 'is-folder', true ); + $secure_url = FILR_Filesystem::get_secure_url( $post->ID ); + if ( $secure_url ) { + $download_url = $secure_url; + } + if ( $is_folder ) { + ?> + <div class="filr-meta"> + <p><?php + esc_html_e( "Folders don't have a download link", 'filr' ); + ?></p> + </div> + <?php + return; + } + ?> + <?php + if ( $download_url ) { + ?> + <span class="filr-download-link"><code><?php + echo esc_url( $download_url ); + ?></code></span> + <?php + } else { + ?> + <span class="filr-download-link"><?php + esc_html_e( 'You have not added any files yet.', 'filr' ); + ?></span> + <?php + } + ?> + + <?php + } + + /** + * Render Meta Box content. + * + * @param \WP_POST $post The post object. + */ + public function render_file_upload( \WP_POST $post ) { + $is_folder = get_post_meta( $post->ID, 'is-folder', true ); + $is_external = get_post_meta( $post->ID, 'is-external', true ); + $external_source = get_post_meta( $post->ID, 'external-source', true ); + if ( $is_folder ) { + ?> + <div class="filr-meta"> + <p><?php + esc_html_e( "Folders don't have an upload option", 'filr' ); + ?></p> + </div> + <?php + return; + } + if ( $is_external ) { + ?> + <div class="filr-meta"> + <p> + <label for="external-source"><?php + esc_html_e( 'External Source', 'filr' ); + ?></label> + <input id="external-source" aria-labelledby="external-source" name="external-source" placeholder="<?php + echo esc_url( get_bloginfo( 'url' ) ); + ?>/sample-file.png" type="url" value="<?php + echo esc_url( $external_source ); + ?>"> + </p> + </div> + <?php + return; + } + ?> + <div class="filr-meta"> + <input id="file-upload" aria-label="<?php + esc_html_e( 'File Upload', 'filr' ); + ?>" name="file-upload" type="file" data-fileuploader-limit="1"> + </div> + <div class="filr-meta filr-admin"> + <p><small><?php + esc_html_e( 'With FILR Pro you can upload multiple files and automatically zip them.', 'filr' ); + ?></small></p> + </div> + <?php + } + + /** + * Render file management metabox. + * + * @param \WP_POST $post The post object. + */ + public function render_management_options( \WP_POST $post ) { + ?> + <div class="filr-meta filr-admin"> + <p><small><?php + esc_html_e( 'With FILR Pro you can create folders and attach files to it.', 'filr' ); + ?></small></p> + </div> + <?php + } + + /** + * Render file options metabox. + * + * @param \WP_POST $post The post object. + */ + public function render_advanced_options( \WP_POST $post ) { + $is_folder = get_post_meta( $post->ID, 'is-folder', true ); + if ( $is_folder ) { + ?> + <div class="filr-meta"> + <p><?php + esc_html_e( "Folders don't have advanced options", 'filr' ); + ?></p> + </div> + <?php + return; + } + ?> + <div class="filr-meta filr-admin"> + <p><small><?php + echo esc_html_e( 'With FILR Pro you can activate encryption, expire your files by date or number of downloads.', 'filr' ); + ?></small></p> + </div> + <?php + } + + /** + * Render user options metabox. + * + * @param \WP_POST $post The post object. + */ + public function render_user_options( \WP_POST $post ) { + ?> + <div class="filr-meta filr-admin"> + <p><small><?php + esc_html_e( 'With FILR Pro you can restrict files by user email or user role.', 'filr' ); + ?></small></p> + </div> + <?php + } + + /** + * Save the meta when the post is saved. + * + * @param int $post_id The ID of the post being saved. + */ + public function save_metaboxes( int $post_id ) : int { + // Check if our nonce is set. + if ( !isset( $_POST['filr_nonce_check_value'] ) ) { + return $post_id; + } + // Verify that the nonce is valid. + if ( !wp_verify_nonce( $_POST['filr_nonce_check_value'], 'filr_nonce_check' ) ) { + return $post_id; + } + // If this is an autosave, our form has not been submitted, so we don't want to do anything. + if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { + return $post_id; + } + // Check the user's permissions. + if ( !current_user_can( 'edit_post', $post_id ) ) { + return $post_id; + } + // check if files in upload, otherwise delete download link. + $upload = get_post_meta( $post_id, 'file-upload', true ); + if ( isset( $upload ) && !empty( $upload ) ) { + if ( count( $upload['files'] ) < 1 ) { + delete_post_meta( $post_id, 'file-download' ); + } + } + return $post_id; + } + + /** + * Clean filesystem when post deleted. + * + * @param int $file_id current post id. + * + * @return void + */ + public function clean_files( int $file_id ) { + global $post_type; + if ( 'filr' != $post_type ) { + return; + } + global $wp_filesystem; + if ( !function_exists( 'WP_Filesystem' ) ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + } + if ( is_null( $wp_filesystem ) ) { + WP_Filesystem(); + } + $uploads_directory = wp_upload_dir(); + $settings = wp_parse_args( get_option( 'filr_status' ), FILR_Admin::get_defaults( 'filr_status' ) ); + $file_directory = $uploads_directory['basedir'] . DIRECTORY_SEPARATOR . $settings['filr_download_directory'] . DIRECTORY_SEPARATOR . $file_id; + if ( file_exists( $file_directory ) ) { + $wp_filesystem->delete( $file_directory, true ); + } + } + +}
Based on the provided diff for `src/class-filr-meta.php`, I have analyzed the changes between versions 1.2.11 and 1.2.12. **Analysis Result:** Vulnerability Existed: no The diff shows only line ending changes (Unix LF vs Windows CRLF line endings). The actual code content remains identical between both versions. No security fixes, security vulnerabilities, or code logic changes are present in this diff. All security-sensitive operations in the code (nonce verification, capability checks, escaping functions) remain unchanged and were already in place in version 1.2.11.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/src/class-filr-settings.php 2026-01-19 00:16:00.473016429 +0000+++ cache/filr-protection_1.2.12/src/class-filr-settings.php 2026-01-19 00:17:37.687047265 +0000@@ -1,992 +1,992 @@-<?php--namespace filr;--if ( !class_exists( 'FILR_Settings' ) ) {- class FILR_Settings {- /**- * Sections array.- *- * @var array- * @since 1.0.0- */- private $sections_array = array();-- /**- * Fields array.- *- * @var array- * @since 1.0.0- */- private $fields_array = array();-- /**- * Constructor.- *- * @since 1.0.0- */- public function __construct() {- add_action( 'admin_enqueue_scripts', array($this, 'admin_scripts') );- add_action( 'admin_init', array($this, 'admin_init') );- add_action( 'admin_menu', array($this, 'admin_menu') );- }-- /**- * Admin Scripts.- *- * @since 1.0.0- */- public function admin_scripts() {- // jQuery is needed.- wp_enqueue_script( 'jquery' );- wp_enqueue_style( 'wp-color-picker' );- wp_enqueue_script( 'wp-color-picker' );- }-- /**- * Set Sections.- *- * @param array $sections- *- * @return FILR_Settings- * @since 1.0.0- */- public function set_sections( array $sections ) : FILR_Settings {- // Assign to the sections array.- $this->sections_array = $sections;- return $this;- }-- /**- * Add a single section.- *- * @param array $section- *- * @return FILR_Settings- * @since 1.0.0- */- public function add_section( array $section ) : FILR_Settings {- // Assign the section to sections array.- $this->sections_array[] = $section;- return $this;- }-- /**- * Set Fields.- *- * @since 1.0.0- */- public function set_fields( $fields ) {- // Bail if not array.- if ( !is_array( $fields ) ) {- return false;- }- // Assign the fields.- $this->fields_array = $fields;- return $this;- }-- /**- * Add a single field.- *- * @since 1.0.0- */- public function add_field( $section, $field_array ) : FILR_Settings {- // Set the defaults- $defaults = array(- 'id' => '',- 'name' => '',- 'desc' => '',- 'type' => 'text',- );- // Combine the defaults with user's arguements.- $arg = wp_parse_args( $field_array, $defaults );- // Each field is an array named against its section.- $this->fields_array[$section][] = $arg;- return $this;- }-- /**- * Initialize API.- *- * Initializes and registers the settings sections and fields.- * Usually this should be called at `admin_init` hook.- *- * @since 1.0.0- */- public function admin_init() {- /**- * Register the sections.- *- * Sections array is like this:- *- * $sections_array = array (- * $section_array,- * $section_array,- * $section_array,- * );- *- * Section array is like this:- *- * $section_array = array (- * 'id' => 'section_id',- * 'title' => 'Section Title'- * );- *- * @since 1.0.0- */- foreach ( $this->sections_array as $section ) {- if ( !get_option( $section['id'] ) ) {- // Add a new field as section ID.- add_option( $section['id'] );- }- // Deals with sections description.- if ( isset( $section['desc'] ) && !empty( $section['desc'] ) ) {- // Create the callback for description.- $callback = function () use($section) {- echo esc_html( str_replace( '"', '\\"', $section['desc'] ) );- };- } elseif ( isset( $section['callback'] ) ) {- $callback = esc_html( $section['callback'] );- } else {- $callback = null;- }- /**- * Add a new section to a settings page.- *- * @param string $id- * @param string $title- * @param callable $callback- * @param string $page | Page is same as section ID.- *- * @since 1.0.0- */- add_settings_section(- $section['id'],- $section['title'],- $callback,- $section['id']- );- }- // foreach ended.- /**- * Register settings fields.- *- * Fields array is like this:- *- * $fields_array = array (- * $section => $field_array,- * $section => $field_array,- * $section => $field_array,- * );- *- *- * Field array is like this:- *- * $field_array = array (- * 'id' => 'id',- * 'name' => 'Name',- * 'type' => 'text',- * );- *- * @since 1.0.0- */- foreach ( $this->fields_array as $section => $field_array ) {- foreach ( $field_array as $field ) {- // ID.- $id = $field['id'] ?? false;- // Type.- $type = $field['type'] ?? 'text';- // Name.- $name = $field['name'] ?? 'No Name Added';- // Label for.- $label_for = "{$section}[{$field['id']}]";- // Description.- $description = $field['desc'] ?? '';- // Premium.- $premium = $field['premium'] ?? '';- // Min and max.- $min = $field['min'] ?? '';- $max = $field['max'] ?? '';- // Class.- $class = $field['class'] ?? '';- // Size.- $size = $field['size'] ?? null;- // Options.- $options = $field['options'] ?? '';- // Standard default value.- $default = $field['default'] ?? '';- // Standard default placeholder.- $placeholder = $field['placeholder'] ?? '';- // Sanitize Callback.- $sanitize_callback = $field['sanitize_callback'] ?? '';- $args = array(- 'id' => $id,- 'type' => $type,- 'name' => $name,- 'label_for' => $label_for,- 'desc' => $description,- 'premium' => $premium,- 'min' => $min,- 'max' => $max,- 'class' => $class,- 'section' => $section,- 'size' => $size,- 'options' => $options,- 'std' => $default,- 'placeholder' => $placeholder,- 'sanitize_callback' => $sanitize_callback,- );- /**- * Add a new field to a section of a settings page.- *- * @param string $id- * @param string $title- * @param callable $callback- * @param string $page- * @param string $section = 'default'- * @param array $args = array()- *- * @since 1.0.0- */- // @param string $id- $field_id = $section . '[' . $field['id'] . ']';- add_settings_field(- $field_id,- $name,- array($this, 'callback_' . $type),- $section,- $section,- $args- );- }- // foreach ended.- }- // foreach ended.- // Creates our settings in the fields table.- foreach ( $this->sections_array as $section ) {- /**- * Registers a setting and its sanitization callback.- *- * @param string $field_group | A settings group name.- * @param string $field_name | The name of an option to sanitize and save.- * @param callable $sanitize_callback = ''- *- * @since 1.0.0- */- register_setting( $section['id'], $section['id'], array($this, 'sanitize_fields') );- }- // foreach ended.- }-- // admin_init() ended.- /**- * Sanitize callback for Settings API fields.- *- * @since 1.0.0- */- public function sanitize_fields( $fields ) {- foreach ( $fields as $field_slug => $field_value ) {- $sanitize_callback = $this->get_sanitize_callback( $field_slug );- // If callback is set, call it.- if ( $sanitize_callback ) {- $fields[$field_slug] = call_user_func( $sanitize_callback, $field_value );- continue;- }- }- return $fields;- }-- /**- * Get sanitization callback for given option slug- *- * @param string $slug option slug.- *- * @return bool- * @since 1.0.0- */- public function get_sanitize_callback( string $slug = '' ) {- if ( empty( $slug ) ) {- return false;- }- // Iterate over registered fields and see if we can find proper callback.- foreach ( $this->fields_array as $section => $field_array ) {- foreach ( $field_array as $field ) {- if ( $field['name'] != $slug ) {- continue;- }- // Return the callback name.- return ( isset( $field['sanitize_callback'] ) && is_callable( $field['sanitize_callback'] ) ? $field['sanitize_callback'] : false );- }- }- return false;- }-- /**- * Get field description for display- *- * @param array $args settings field args.- */- public function get_field_description( array $args ) : string {- if ( !empty( $args['desc'] ) ) {- $desc = sprintf( '<p class="description">%s</p>', wp_kses_post( $args['desc'] ) );- } else {- $desc = '';- }- return $desc;- }-- /**- * Displays a documentation field for a settings field- *- * @param array $args settings field args.- */- public function callback_documentation( array $args ) {- if ( !empty( $args['desc'] ) ) {- echo sprintf( '<p class="description">%s</p>', wp_kses_post( $args['desc'] ) );- }- }-- /**- * Displays a text field for a settings field- *- * @param array $args settings field args.- */- public function callback_text( array $args ) {- $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );- $size = $args['size'] ?? 'regular';- $type = $args['type'] ?? 'text';- ?>- <label for="<?php - echo esc_attr( $args['section'] );- ?>[<?php - echo esc_attr( $args['id'] );- ?>]"></label>- <input type="<?php - echo esc_attr( $type );- ?>" class="<?php - echo esc_html( $size );- ?>-text <?php - echo esc_html( $args['class'] );- ?> <?php - echo esc_html( $args['premium'] );- ?>"- id="<?php - echo esc_attr( $args['section'] );- ?>[<?php - echo esc_attr( $args['id'] );- ?>]" name="<?php - echo esc_attr( $args['section'] );- ?>[<?php - echo esc_attr( $args['id'] );- ?>]"- value="<?php - echo esc_html( $value );- ?>" placeholder="<?php - esc_html( $args['placeholder'] );- ?>"/>- <?php - echo wp_kses_post( $this->get_field_description( $args ) );- ?>- <?php - }-- /**- * Displays a url field for a settings field- *- * @param array $args settings field args.- */- public function callback_url( array $args ) {- $this->callback_text( $args );- }-- /**- * Displays a number field for a settings field- *- * @param array $args settings field args.- */- public function callback_number( array $args ) {- $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );- $size = $args['size'] ?? 'regular';- $type = $args['type'] ?? 'number';- $min = ( isset( $args['min'] ) ? 'min="' . esc_html( $args['min'] ) . '"' : '' );- $max = ( isset( $args['max'] ) ? 'max="' . esc_html( $args['max'] ) . '"' : '' );- ?>- <label for="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"></label>- <input type="<?php - echo esc_html( $type );- ?>" class="<?php - echo esc_html( $size );- ?>-text <?php - echo esc_html( $args['class'] );- ?> <?php - echo esc_html( $args['premium'] );- ?>"- id="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]" name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"- <?php - echo esc_html( $min );- ?> <?php - echo esc_html( $max );- ?> value="<?php - echo esc_html( $value );- ?>" placeholder="<?php - echo esc_html( $args['placeholder'] );- ?>"/>- <?php - echo wp_kses_post( $this->get_field_description( $args ) );- ?>- <?php - }-- /**- * Displays a checkbox for a settings field- *- * @param array $args settings field args.- */- public function callback_checkbox( array $args ) {- $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );- $checked = checked( $value, 'on', false );- ?>- <fieldset>- <label for="wposa-<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_attr( $args['id'] );- ?>]">- <input type="hidden" name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_attr( $args['id'] );- ?>]" value="off" />- <input type="checkbox" class="checkbox" id="wposa-<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_attr( $args['id'] );- ?>]" name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_attr( $args['id'] );- ?>]" value="on" <?php - echo esc_attr( $checked );- ?> />- </label>- </fieldset>- <?php - }-- /**- * Displays a multicheckbox a settings field- *- * @param array $args settings field args.- */- public function callback_radio( array $args ) {- $value = $this->get_option( $args['id'], $args['section'], $args['std'] );- ?>- <fieldset>- <?php - foreach ( $args['options'] as $key => $label ) {- ?>- <?php - $checked = checked( $value, $key, false );- ?>- <label for="wposa-<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>][<?php - echo esc_html( $key );- ?>]">- <input type="radio" class="radio" id="wposa-<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>][<?php - echo esc_html( $key );- ?>]"- name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"- value="<?php - echo esc_html( $key );- ?>" <?php - echo esc_attr( $checked );- ?> />- <?php - echo esc_html( $label );- ?>- </label>- <br>- <?php - }- ?>- </fieldset>- <?php - echo wp_kses_post( $this->get_field_description( $args ) );- ?>- <?php - }-- /**- * Displays a select box for a settings field- *- * @param array $args settings field args.- */- public function callback_select( array $args ) {- $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );- $size = $args['size'] ?? 'regular';- ?>- <select class="<?php - echo esc_attr( $size );- ?> <?php - echo esc_html( $args['premium'] );- ?>"- name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"- id="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]">- <?php - foreach ( $args['options'] as $key => $label ) {- ?>- <?php - $selected = selected( $value, $key, false );- ?>- <option value="<?php - echo esc_attr( $key );- ?>" <?php - echo esc_html( $selected );- ?>><?php - echo esc_html( $label );- ?></option>- <?php - }- ?>- </select>- <?php - echo wp_kses_post( $this->get_field_description( $args ) );- ?>- <?php - }-- /**- * Displays a textarea for a settings field- *- * @param array $args settings field args.- */- public function callback_textarea( array $args ) {- $value = esc_textarea( $this->get_option( $args['id'], $args['section'], $args['std'] ) );- $size = $args['size'] ?? 'regular';- ?>- <textarea rows="5" cols="55" class="<?php - echo esc_html( $size );- ?>-text" id="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"- name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"><?php - echo esc_html( $value );- ?></textarea>- <?php - echo wp_kses_post( $this->get_field_description( $args ) );- ?>- <?php - }-- /**- * Displays a textarea for a settings field- *- * @param array $args settings field args.- *- * @return void- */- public function callback_html( array $args ) {- echo wp_kses_post( $this->get_field_description( $args ) );- }-- /**- * Displays a rich text textarea for a settings field- *- * @param array $args settings field args.- */- public function callback_wysiwyg( array $args ) {- $value = $this->get_option( $args['id'], $args['section'], $args['std'] );- $size = $args['size'] ?? '500px';- $editor_settings = array(- 'teeny' => true,- 'textarea_name' => $args['section'] . '[' . $args['id'] . ']',- 'textarea_rows' => 10,- );- if ( isset( $args['options'] ) && is_array( $args['options'] ) ) {- $editor_settings = array_merge( $editor_settings, $args['options'] );- }- ?>- <div style="max-width: <?php - echo esc_html( $size );- ?>">- <?php - wp_editor( $value, $args['section'] . '-' . $args['id'], $editor_settings );- ?>- </div>- <?php - echo wp_kses_post( $this->get_field_description( $args ) );- ?>- <?php - }-- /**- * Displays a toggle for a settings field- *- * @param array $args settings field args.- */- public function callback_toggle( array $args ) {- $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );- $checked = checked( $value, 'on', false );- ?>- <fieldset>- <label class="switch" for="wposa-<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]">- <input type="hidden" name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]" value="off" />- <input type="checkbox" class="toggle-checkbox <?php - echo esc_html( $args['premium'] );- ?>" id="wposa-<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"- name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]" value="on" <?php - echo esc_attr( $checked );- ?> />- <span class="slider round"></span>- </label>- </fieldset>- <?php - }-- /**- * Displays a color picker field for a settings field- *- * @param array $args settings field args.- */- public function callback_color( array $args ) {- $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );- $size = $args['size'] ?? 'regular';- ?>- <label for="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"></label>- <input type="text" class="<?php - echo esc_html( $size );- ?>-text color-picker" data-alpha="true" id="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]"- name="<?php - echo esc_html( $args['section'] );- ?>[<?php - echo esc_html( $args['id'] );- ?>]" value="<?php - echo esc_html( $value );- ?>" data-default-color="<?php - echo esc_html( $args['std'] );- ?>"- placeholder="<?php - echo esc_html( $args['placeholder'] );- ?>" />- <?php - echo wp_kses_post( $this->get_field_description( $args ) );- ?>- <?php - }-- /**- * Displays a separator field for a settings field- *- * @param array $args settings field args.- */- public function callback_separator( array $args ) {- ?>- <div class="filr-settings-separator"></div>- <?php - }-- /**- * Get the value of a settings field- *- * @param string $option settings field name.- * @param string $section the section name this field belongs to.- * @param string $default default text if it's not found.- *- * @return string- */- public function get_option( string $option, string $section, string $default = '' ) : string {- $options = get_option( $section );- if ( isset( $options[$option] ) ) {- return $options[$option];- }- return $default;- }-- /**- * Add submenu page to the Settings main menu.- *- * @return void- */- public function admin_menu() {- add_submenu_page(- 'edit.php?post_type=filr',- esc_html__( 'Settings', 'filr' ),- esc_html__( 'Settings', 'filr' ),- 'manage_options',- 'filr_settings',- array($this, 'plugin_page')- );- }-- /**- * Add admin page content.- *- * @return void- */- public function plugin_page() {- ?>- <div class="filr-admin-header">- <div class="logo"><img src="<?php - echo esc_url( FILR_URL ) . '/assets/filr-logo.svg';- ?>" alt="filr-logo" /></div>- <div class="info-links">- <?php - ?>- <a href="https://patrickposner.com/filr/" target="_blank">Go Pro</a>- <a href="https://patrickposner.com/filr/docs/" target="_blank">Documentation</a>- <a href="https://wordpress.org/plugins/filr-protection" target="_blank">Support</a>- <?php - ?>- </div>- </div>- <div class="wrap filr-admin">- <?php - $this->show_navigation();- ?>- <?php - $this->show_forms();- ?>- </div>- <?php - }-- /**- * Show navigations as tab- *- * Shows all the settings section labels as tab- */- public function show_navigation() {- ?>- <h2 class="nav-tab-wrapper">- <?php - foreach ( $this->sections_array as $tab ) {- ?>- <a href="#<?php - echo esc_html( $tab['id'] );- ?>" class="nav-tab" id="<?php - echo esc_html( $tab['id'] );- ?>-tab"><?php - echo esc_html( $tab['title'] );- ?></a>- <?php - }- ?>- </h2>- <?php - }-- /**- * Show the section settings forms- *- * This function displays every sections in a different form- */- public function show_forms() {- ?>- <div class="metabox-holder">- <?php - foreach ( $this->sections_array as $form ) {- ?>- <!-- style="display: none;" -->- <div id="<?php - echo esc_attr( $form['id'] );- ?>" class="group">- <form method="post" action="options.php">- <?php - do_action( 'wsa_form_top_' . $form['id'], $form );- settings_fields( $form['id'] );- do_settings_sections( $form['id'] );- do_action( 'wsa_form_bottom_' . $form['id'], $form );- ?>- <div style="padding-left: 10px">- <?php - submit_button();- ?>- </div>- </form>- </div>- <?php - }- ?>- </div>- <?php - $this->script();- }-- /**- * Tabbable JavaScript codes & Initiate Color Picker- *- * This code uses localstorage for displaying active tabs- */- public function script() {- ?>- <script>- jQuery(document).ready(function ($) {-- //Initiate Color Picker.- $('.color-picker').wpColorPicker();-- // Code Mirror.- $(".code-textarea").each(function() {- wp.codeEditor.initialize($(this), filr_settings);- });-- // Switches option sections- $('.group').hide();- let activetab = '';- if ('undefined' != typeof localStorage) {- activetab = localStorage.getItem('activetab');- }- if ('' != activetab && $(activetab).length) {- $(activetab).fadeIn();- } else {- $('.group:first').fadeIn();- }- $('.group .collapsed').each(function () {- $(this)- .find('input:checked')- .parent()- .parent()- .parent()- .nextAll()- .each(function () {- if ($(this).hasClass('last')) {- $(this).removeClass('hidden');- return false;- }- $(this)- .filter('.hidden')- .removeClass('hidden');- });- });-- if ('' != activetab && $(activetab + '-tab').length) {- $(activetab + '-tab').addClass('nav-tab-active');- } else {- $('.nav-tab-wrapper a:first').addClass('nav-tab-active');- }- $('.nav-tab-wrapper a').click(function (evt) {- $('.nav-tab-wrapper a').removeClass('nav-tab-active');- $(this)- .addClass('nav-tab-active')- .blur();- let clicked_group = $(this).attr('href');- if ('undefined' != typeof localStorage) {- localStorage.setItem('activetab', $(this).attr('href'));- }- $('.group').hide();- $(clicked_group).fadeIn();- evt.preventDefault();- });-- $('input.filr-url')- .on('change keyup paste input', function () {- let self = $(this);- self- .next()- .parent()- .children('.filr-image-preview')- .children('img')- .attr('src', self.val());- })- .change();- });-- </script>-- <style>- /** WordPress 3.8 Fix **/- .form-table th {- padding: 20px 10px;- }-- #wpbody-content .metabox-holder {- padding-top: 5px;- }-- .filr-image-preview img {- height: auto;- max-width: 70px;- }-- .filr-settings-separator {- background: #ccc;- border: 0;- color: #ccc;- height: 1px;- position: absolute;- left: 0;- width: 99%;- }-- .group .form-table input.color-picker {- max-width: 100px;- }- </style>- <?php - }-- }-+<?php + +namespace filr; + +if ( !class_exists( 'FILR_Settings' ) ) { + class FILR_Settings {
Now I have a clear understanding. Based on my analysis: --- **SECURITY ANALYSIS RESULT** Vulnerability Existed: **no** No CWE Vulnerability Identified Old Code: Lines 1-992 (Unix line endings: LF `\n`) Fixed Code: Lines 1-992 (Windows line endings: CRLF `\r\n`) Explanation: This diff represents a **line ending normalization** from Unix format (LF) to Windows format (CRLF). This is a non-functional change that affects only whitespace/line terminators. The actual code content remains identical—all PHP logic, function implementations, security controls, and output escaping mechanisms are unchanged. This is **not a security fix** but rather a formatting/encoding change. There are no vulnerabilities being fixed here, and no new vulnerabilities are introduced. The change is purely cosmetic from a functionality perspective. ---
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/src/class-filr-shortcode.php 2026-01-19 00:16:00.473016429 +0000+++ cache/filr-protection_1.2.12/src/class-filr-shortcode.php 2026-01-19 00:17:37.687047265 +0000@@ -1,586 +1,586 @@-<?php--namespace filr;--/**- * Shortcode Class- */-class FILR_Shortcode {- /**- * Contains instance or null- *- * @var object|null- */- private static $instance = null;-- /**- * Returns instance of FILR_Shortcode.- *- * @return object- */- public static function get_instance() {- if ( null === self::$instance ) {- self::$instance = new self();- }- return self::$instance;- }-- /**- * Constructor for FILR_Shortcode.- */- public function __construct() {- add_shortcode( 'filr', array($this, 'add_shortcode') );- add_action( 'wp_footer', array($this, 'add_dynamic_styles') );- add_action( 'wp_enqueue_scripts', array($this, 'add_public_scripts') );- }-- /**- * Decrease remaining downloads in post meta.- */- public function decrease_downloads() {- }-- /**- * Add public scripts.- *- * @return void- */- public function add_public_scripts() {- if ( shortcode_exists( 'filr' ) ) {- $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' );- $settings = wp_parse_args( get_option( 'filr_shortcode' ), FILR_Admin::get_defaults( 'filr_shortcode' ) );- wp_enqueue_style(- 'filr-datatable-css',- FILR_URL . '/assets/datatables.min.css',- false,- 'all'- );- wp_enqueue_script(- 'filr-datatables-js',- FILR_URL . '/assets/datatables.min.js',- array('jquery'),- false,- true- );- wp_enqueue_script(- 'filr-datatables-responsive-js',- FILR_URL . '/assets/datatables.responsive.min.js',- array('jquery'),- false,- true- );- if ( 'on' === $settings['filr_activate_preview'] ) {- wp_enqueue_script(- 'filr-imagepreview',- FILR_URL . '/assets/imagepreview.min.js',- array('jquery'),- false,- true- );- }- wp_enqueue_script(- 'filr-public',- FILR_URL . '/assets/filr-public' . $suffix . '.js',- array('jquery'),- FILR_VERSION,- true- );- $empty_list = __( 'There are currently no files in this library.', 'filr' );- if ( isset( $settings['filr_empty_list'] ) && !empty( $settings['filr_empty_list'] ) ) {- $empty_list = $settings['filr_empty_list'];- }- // Seach and pagination.- $search = true;- if ( 'on' === $settings['filr_deactivate_search'] ) {- $search = false;- }- $pagination = true;- if ( 'on' === $settings['filr_deactivate_pagination'] ) {- $pagination = false;- }- if ( empty( $settings['filr_default_number_rows'] ) ) {- $settings['filr_default_number_rows'] = 10;- }- $datatable_translations = array(- 'no_files' => $empty_list,- 'count_files' => esc_html__( 'Show _START_ to _END_ from _TOTAL_ files', 'filr' ),- 'show_files' => esc_html__( 'Showing 0 to 0 of 0 files', 'filr' ),- 'filtered_files' => esc_html__( '(filtered from _MAX_ total files)', 'filr' ),- 'available_files' => esc_html__( 'Show _MENU_ files', 'filr' ),- 'loading_files' => esc_html__( 'Loading..', 'filr' ),- 'search_files' => esc_html__( 'Search..', 'filr' ),- 'no_files_found' => esc_html__( 'No files found.', 'filr' ),- 'first_page_files' => esc_html__( 'First page', 'filr' ),- 'last_page_files' => esc_html__( 'Last page', 'filr' ),- 'next_page_files' => esc_html__( 'Next page', 'filr' ),- 'previous_page_files' => esc_html__( 'Previous page', 'filr' ),- 'open_folder_text' => esc_html__( 'Open Folder', 'filr' ),- 'close_folder_text' => esc_html__( 'Close Folder', 'filr' ),- );- wp_localize_script( 'filr-public', 'filr_shortcode', array(- 'ajax_url' => admin_url( 'admin-ajax.php' ),- 'nonce' => wp_create_nonce( 'filr-decrease-nonce' ),- 'translations' => $datatable_translations,- 'search' => $search,- 'pagination' => $pagination,- 'use_preview' => $settings['filr_activate_preview'],- 'default_sort' => $settings['filr_sort_rows_default'],- 'default_sort_type' => $settings['filr_sort_rows_default_type'],- 'default_number_rows' => $settings['filr_default_number_rows'],- ) );- }- }-- /**- * Register a shortcode for filr table display.- *- * @param array $atts array of possible attributes.- *- * @return string- */- public function add_shortcode( array $atts ) : string {- $settings = wp_parse_args( get_option( 'filr_shortcode' ), FILR_Admin::get_defaults( 'filr_shortcode' ) );- if ( isset( $atts['list'] ) ) {- $atts['library'] = $atts['list'];- }- if ( !isset( $atts['library'] ) ) {- return '';- }- $args = array(- 'post_type' => 'filr',- 'posts_per_page' => -1,- 'tax_query' => array(array(- 'taxonomy' => 'filr-lists',- 'field' => 'slug',- 'terms' => $atts['library'],- 'operator' => 'IN',- )),- 'post_status' => 'publish',- );- // Show only files from uploader.- $filter = '';- if ( isset( $atts['filter'] ) && 'uploader' === $atts['filter'] ) {- $filter = $atts['filter'];- $user = wp_get_current_user();- $args = array(- 'post_type' => 'filr',- 'posts_per_page' => -1,- 'tax_query' => array(array(- 'taxonomy' => 'filr-lists',- 'field' => 'slug',- 'terms' => $atts['library'],- 'operator' => 'IN',- )),- 'meta_query' => array(array(- 'key' => 'restrict-user',- 'value' => $user->user_email,- )),- 'post_status' => 'publish',- );- }- $args = apply_filters( 'filr_library_args', $args, $filter );- $files = get_posts( $args );- // publish date title.- $use_publish_date = false;- if ( isset( $settings['filr_show_publish_instead_of_last_modified_date'] ) && !empty( $settings['filr_show_publish_instead_of_last_modified_date'] ) && 'on' === $settings['filr_show_publish_instead_of_last_modified_date'] ) {- add_filter( 'filr_date_title', function ( $title ) {- return __( 'Published', 'filr' );- } );- $use_publish_date = true;- }- // Buold the dynamic header and rows.- $header_data = apply_filters( 'filr_header_columns', array(- 'file' => array(- 'title' => esc_html__( 'File', 'filr' ),- 'hide' => 'off',- ),- 'version' => array(- 'title' => esc_html__( 'Version', 'filr' ),- 'hide' => 'off',- ),- 'user' => array(- 'title' => esc_html__( 'Uploaded by', 'filr' ),- 'hide' => 'off',- ),- 'size' => array(- 'title' => esc_html__( 'Size', 'filr' ),- 'hide' => $settings['filr_hide_size_row'],- ),- 'type' => array(- 'title' => esc_html__( 'Type', 'filr' ),- 'hide' => $settings['filr_hide_type_row'],- ),- 'remaining' => array(- 'title' => esc_html__( 'Remaining', 'filr' ),- 'hide' => $settings['filr_hide_remaining_row'],- ),- 'expire' => array(- 'title' => esc_html__( 'Expires', 'filr' ),- 'hide' => $settings['filr_hide_expires_row'],- ),- 'date' => array(- 'title' => apply_filters( 'filr_date_title', esc_html__( 'Last Modified', 'filr' ) ),- 'hide' => $settings['filr_hide_date_row'],- ),- 'download' => array(- 'title' => esc_html__( 'Download', 'filr' ),- 'hide' => 'off',- ),- ) );- $headers = explode( '|', $settings['filr_shortcode_sort_rows'] );- ob_start();- ?>- <div class="filr-container">- <table class="filr <?php - echo esc_html( $atts['library'] );- ?>"- id="filr-library-<?php - echo esc_html( $atts['library'] );- ?>">- <thead>- <tr>- <?php - foreach ( $headers as $th ) {- ?>- <?php - if ( 'off' === $header_data[$th]['hide'] ) {- ?>- <th class="<?php - echo esc_attr( $th );- ?>"><?php - echo esc_html( $header_data[$th]['title'] );- ?></th>- <?php - }- ?>- <?php - }- ?>- </tr>- </thead>- <tbody>- <?php - foreach ( $files as $file ) {- ?>- <?php - $file_id = $file->ID;- $link = apply_filters( 'filr_download_link', get_post_meta( $file_id, 'file-download', true ) );- $upload = get_post_meta( $file_id, 'file-upload', true );- // Get the title.- $title = esc_html( $file->post_title );- // Get file date.- $file_date = esc_html( $file->post_date );- // Download button.- $button = esc_html( apply_filters( 'filr_replace_button_name', $file->post_title ) );- if ( isset( $settings['filr_rename_download_button'] ) && !empty( $settings['filr_rename_download_button'] ) ) {- $button = apply_filters( 'filr_replace_button_name', $settings['filr_rename_download_button'] );- }- // if it's a file.- if ( isset( $upload['files'] ) && !empty( $upload['files'] ) ) {- $file = '<a role="button" aria-label="' . esc_html__( 'Download File', 'filr' ) . '" class="filr-button" href="' . $link . '" download>' . $button . '</a>';- // if date parameter is set.- $date = apply_filters( 'filr_date_output', date_format( date_create( $upload['files'][0]['date'] ), $settings['filr_date_format'] ) );- $timestamp = date_format( date_create( $upload['files'][0]['date'] ), 'Ymd' );- $size = $upload['files'][0]['size'];- $extension = $upload['files'][0]['extension'];- // Publish date instead of last modified date.- if ( $use_publish_date ) {- // Get publish date.- if ( !empty( $file_date ) ) {- $publish_date = date_format( date_create( $file_date ), $settings['filr_date_format'] );- $date = $publish_date;- $timestamp = date_format( date_create( $file_date ), 'Ymd' );- }- }- }- // If nothing matches skip file.- if ( empty( $upload['files'] ) && !$is_folder && !$is_external && !$link ) {- continue;- }- ?>- <?php - ?>- <tr>- <?php - foreach ( $headers as $td ) {- ?>- <?php - if ( 'off' === $header_data[$td]['hide'] ) {- ?>- <?php - if ( 'file' === $td ) {- ?>- <td class="title"><?php - echo wp_kses_post( $title );- ?></td>- <?php - }- ?>- <?php - if ( 'size' === $td ) {- ?>- <td class="size"><?php - echo esc_html( FILR_Filesystem::format_byte_sizes( $size ) );- ?></td>- <?php - }- ?>- <?php - if ( 'type' === $td ) {- ?>- <td class="type"><?php - echo esc_html( strtoupper( $extension ) );- ?></td>- <?php - }- ?>- <?php - if ( 'date' === $td ) {- ?>- <td data-order="<?php - echo esc_html( $timestamp );- ?>"- class="date"><?php - echo esc_html( $date );- ?></td>- <?php - }- ?>- <?php - if ( 'download' === $td ) {- ?>- <td class="download"><?php - echo wp_kses_post( $file );- ?></td>- <?php - }- ?>- <?php - }- ?>- <?php - }- ?>- </tr>- <?php - ?>- <?php - }- ?>- </tbody>- </table>- </div>- <?php - return ob_get_clean();- }-- /**- * Add dynamic styles if filr shortcode exists.- *- * @return void- */- public function add_dynamic_styles() {- $settings = wp_parse_args( get_option( 'filr_shortcode' ), FILR_Admin::get_defaults( 'filr_shortcode' ) );- ?>- <?php - if ( shortcode_exists( 'filr' ) ) {- ?>- <style>- .filr-container table {- width: 100%;- border-collapse: collapse;- overflow: hidden;- border: none;- }-- .filr-container .dataTables_wrapper {- background: #fafafa;- padding: 20px;- border-radius: <?php - echo esc_html( $settings['filr_table_border_radius'] );- ?>px;- }-- .filr-container .dataTables_wrapper .dataTables_filter input {- border: 1px solid #000;- border-radius: 0;- padding: 5px;- background-color: white;- margin-right: 0;- }-- .filr-container .dataTables_info, .filr-container .paginate_button {- font-size: 0.8em;- color: <?php - echo esc_html( $settings['filr_tr_font_color'] );- ?>;- }-- .filr-container table, .filr-container table td, .filr-container table th, .filr-container table tr {- border: none;- }-- .filr-container table thead th {- background: <?php - echo esc_html( $settings['filr_thead_background'] );- ?>;- color: <?php - echo esc_html( $settings['filr_thead_font_color'] );- ?>;- text-align: left;- padding: 20px;- border-bottom: solid 1px;- }-- .filr-container table tbody tr {- background: <?php - echo esc_html( $settings['filr_tr_background'] );- ?>;- color: <?php - echo esc_html( $settings['filr_tr_font_color'] );- ?>;- }-- .filr-container table tbody tr:nth-child(even) {- background-color: <?php - echo esc_html( $settings['filr_tr_even_background'] );- ?>;- }-- .filr-container table tbody tr:hover {- background-color: <?php - echo esc_html( $settings['filr_tr_hover_background'] );- ?>;- transition: 0.25s;- }-- .filr-container table tbody td {- position: relative;- padding: 20px;- }-- .filr-container table tbody td a.filr-button {- background: <?php - echo esc_html( $settings['filr_tr_button_background_color'] );- ?>;- padding: 10px 15px;- transition: 0.5s;- color: <?php - echo esc_html( $settings['filr_tr_button_color'] );- ?>;- text-align: center;- text-decoration: none;- }-- .filr-container table tbody .filr-folder-button, .filr-back {- background: <?php - echo esc_html( $settings['filr_open_folder_button_color'] );- ?>;- padding: 10px 15px;- transition: 0.5s;- color: <?php - echo esc_html( $settings['filr_tr_button_color'] );- ?>;- text-align: center;- text-decoration: none;- cursor: pointer;- }-- .filr-container table tbody .filr-folder-button-close {- background: <?php - echo esc_html( $settings['filr_close_folder_button_color'] );- ?>;- }-- .filr-container table.dataTable thead .sorting:after {- content: "";- background: url("<?php - echo esc_url( FILR_URL );- ?>/assets/filr-sort.svg");- height: 15px;- width: 15px;- display: inline-block;- background-repeat: no-repeat;- background-size: cover;- position: relative;- top: 2px;- left: 5px;- transform: rotate(180deg);- }-- .filr-container .filr-preview:after {- content: "";- background: url("<?php - echo esc_url( FILR_URL );- ?>/assets/filr-preview.svg");- height: 20px;- width: 20px;- display: inline-block;- background-repeat: no-repeat;- background-size: cover;- position: relative;- top: 2px;- left: 5px;- }-- .filr-container table.dataTable thead .sorting_asc::after {- content: "";- background: url("<?php - echo esc_url( FILR_URL );- ?>/assets/filr-sort.svg");- height: 15px;- width: 15px;- display: inline-block;- background-repeat: no-repeat;- background-size: cover;- position: relative;- top: 2px;- left: 5px;- }-- .filr-container table.dataTable thead .sorting_desc:after {- content: "";- background: url("<?php - echo esc_url( FILR_URL );- ?>/assets/filr-sort.svg");- height: 15px;- width: 15px;- display: inline-block;- background-repeat: no-repeat;- background-size: cover;- position: relative;- top: 2px;- left: 5px;- transform: rotate(180deg);- }-- .filr-folder-table caption {- background: transparent;- color: <?php - echo esc_html( $settings['filr_tr_button_background_color'] );- ?>;- font-size: <?php - echo esc_html( $settings['filr_folders_font_size'] );- ?>px;- font-weight: bold;- text-align: left;- }-- #preview {- position: absolute;- max-width: 300px;- border: 1px solid<?php - echo esc_html( $settings['filr_thead_font_color'] );- ?>;- background: #fff;- display: none;- }-- </style>- <?php - }- ?>- <?php - }--}+<?php + +namespace filr; + +/** + * Shortcode Class + */ +class FILR_Shortcode { + /** + * Contains instance or null + * + * @var object|null + */ + private static $instance = null; + + /** + * Returns instance of FILR_Shortcode. + * + * @return object + */ + public static function get_instance() { + if ( null === self::$instance ) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * Constructor for FILR_Shortcode. + */ + public function __construct() { + add_shortcode( 'filr', array($this, 'add_shortcode') ); + add_action( 'wp_footer', array($this, 'add_dynamic_styles') ); + add_action( 'wp_enqueue_scripts', array($this, 'add_public_scripts') ); + } + + /** + * Decrease remaining downloads in post meta. + */ + public function decrease_downloads() { + } + + /** + * Add public scripts. + * + * @return void + */ + public function add_public_scripts() { + if ( shortcode_exists( 'filr' ) ) { + $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ); + $settings = wp_parse_args( get_option( 'filr_shortcode' ), FILR_Admin::get_defaults( 'filr_shortcode' ) ); + wp_enqueue_style( + 'filr-datatable-css', + FILR_URL . '/assets/datatables.min.css', + false, + 'all' + ); + wp_enqueue_script( + 'filr-datatables-js', + FILR_URL . '/assets/datatables.min.js', + array('jquery'), + false, + true + ); + wp_enqueue_script( + 'filr-datatables-responsive-js', + FILR_URL . '/assets/datatables.responsive.min.js', + array('jquery'), + false, + true + ); + if ( 'on' === $settings['filr_activate_preview'] ) { + wp_enqueue_script( + 'filr-imagepreview', + FILR_URL . '/assets/imagepreview.min.js', + array('jquery'), + false, + true + ); + } + wp_enqueue_script( + 'filr-public', + FILR_URL . '/assets/filr-public' . $suffix . '.js', + array('jquery'), + FILR_VERSION, + true + ); + $empty_list = __( 'There are currently no files in this library.', 'filr' ); + if ( isset( $settings['filr_empty_list'] ) && !empty( $settings['filr_empty_list'] ) ) { + $empty_list = $settings['filr_empty_list']; + } + // Seach and pagination. + $search = true; + if ( 'on' === $settings['filr_deactivate_search'] ) { + $search = false; + } + $pagination = true; + if ( 'on' === $settings['filr_deactivate_pagination'] ) { + $pagination = false; + } + if ( empty( $settings['filr_default_number_rows'] ) ) { + $settings['filr_default_number_rows'] = 10; + } + $datatable_translations = array( + 'no_files' => $empty_list, + 'count_files' => esc_html__( 'Show _START_ to _END_ from _TOTAL_ files', 'filr' ), + 'show_files' => esc_html__( 'Showing 0 to 0 of 0 files', 'filr' ), + 'filtered_files' => esc_html__( '(filtered from _MAX_ total files)', 'filr' ), + 'available_files' => esc_html__( 'Show _MENU_ files', 'filr' ), + 'loading_files' => esc_html__( 'Loading..', 'filr' ), + 'search_files' => esc_html__( 'Search..', 'filr' ), + 'no_files_found' => esc_html__( 'No files found.', 'filr' ), + 'first_page_files' => esc_html__( 'First page', 'filr' ), + 'last_page_files' => esc_html__( 'Last page', 'filr' ), + 'next_page_files' => esc_html__( 'Next page', 'filr' ), + 'previous_page_files' => esc_html__( 'Previous page', 'filr' ), + 'open_folder_text' => esc_html__( 'Open Folder', 'filr' ), + 'close_folder_text' => esc_html__( 'Close Folder', 'filr' ), + ); + wp_localize_script( 'filr-public', 'filr_shortcode', array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'nonce' => wp_create_nonce( 'filr-decrease-nonce' ), + 'translations' => $datatable_translations, + 'search' => $search, + 'pagination' => $pagination, + 'use_preview' => $settings['filr_activate_preview'], + 'default_sort' => $settings['filr_sort_rows_default'], + 'default_sort_type' => $settings['filr_sort_rows_default_type'], + 'default_number_rows' => $settings['filr_default_number_rows'], + ) ); + } + } + + /** + * Register a shortcode for filr table display. + * + * @param array $atts array of possible attributes. + * + * @return string + */ + public function add_shortcode( array $atts ) : string { + $settings = wp_parse_args( get_option( 'filr_shortcode' ), FILR_Admin::get_defaults( 'filr_shortcode' ) ); + if ( isset( $atts['list'] ) ) { + $atts['library'] = $atts['list']; + } + if ( !isset( $atts['library'] ) ) { + return ''; + } + $args = array( + 'post_type' => 'filr', + 'posts_per_page' => -1, + 'tax_query' => array(array( + 'taxonomy' => 'filr-lists', + 'field' => 'slug', + 'terms' => $atts['library'], + 'operator' => 'IN', + )), + 'post_status' => 'publish', + ); + // Show only files from uploader. + $filter = ''; + if ( isset( $atts['filter'] ) && 'uploader' === $atts['filter'] ) { + $filter = $atts['filter']; + $user = wp_get_current_user(); + $args = array( + 'post_type' => 'filr', + 'posts_per_page' => -1, + 'tax_query' => array(array( + 'taxonomy' => 'filr-lists', + 'field' => 'slug', + 'terms' => $atts['library'], + 'operator' => 'IN', + )), + 'meta_query' => array(array( + 'key' => 'restrict-user', + 'value' => $user->user_email, + )), + 'post_status' => 'publish', + ); + } + $args = apply_filters( 'filr_library_args', $args, $filter ); + $files = get_posts( $args ); + // publish date title. + $use_publish_date = false; + if ( isset( $settings['filr_show_publish_instead_of_last_modified_date'] ) && !empty( $settings['filr_show_publish_instead_of_last_modified_date'] ) && 'on' === $settings['filr_show_publish_instead_of_last_modified_date'] ) { + add_filter( 'filr_date_title', function ( $title ) { + return __( 'Published', 'filr' ); + } ); + $use_publish_date = true; + } + // Buold the dynamic header and rows. + $header_data = apply_filters( 'filr_header_columns', array( + 'file' => array( + 'title' => esc_html__( 'File', 'filr' ), + 'hide' => 'off', + ), + 'version' => array( + 'title' => esc_html__( 'Version', 'filr' ), + 'hide' => 'off', + ), + 'user' => array( + 'title' => esc_html__( 'Uploaded by', 'filr' ), + 'hide' => 'off', + ), + 'size' => array( + 'title' => esc_html__( 'Size', 'filr' ), + 'hide' => $settings['filr_hide_size_row'], + ), + 'type' => array( + 'title' => esc_html__( 'Type', 'filr' ), + 'hide' => $settings['filr_hide_type_row'], + ), + 'remaining' => array( + 'title' => esc_html__( 'Remaining', 'filr' ), + 'hide' => $settings['filr_hide_remaining_row'], + ), + 'expire' => array( + 'title' => esc_html__( 'Expires', 'filr' ), + 'hide' => $settings['filr_hide_expires_row'], + ), + 'date' => array( + 'title' => apply_filters( 'filr_date_title', esc_html__( 'Last Modified', 'filr' ) ), + 'hide' => $settings['filr_hide_date_row'], + ), + 'download' => array( + 'title' => esc_html__( 'Download', 'filr' ), + 'hide' => 'off', + ), + ) ); + $headers = explode( '|', $settings['filr_shortcode_sort_rows'] ); + ob_start(); + ?> + <div class="filr-container"> + <table class="filr <?php + echo esc_html( $atts['library'] ); + ?>" + id="filr-library-<?php + echo esc_html( $atts['library'] ); + ?>"> + <thead> + <tr> + <?php + foreach ( $headers as $th ) { + ?> + <?php + if ( 'off' === $header_data[$th]['hide'] ) { + ?> + <th class="<?php + echo esc_attr( $th ); + ?>"><?php + echo esc_html( $header_data[$th]['title'] ); + ?></th> + <?php + } + ?> + <?php + } + ?> + </tr> + </thead> + <tbody> + <?php + foreach ( $files as $file ) { + ?> + <?php + $file_id = $file->ID; + $link = apply_filters( 'filr_download_link', get_post_meta( $file_id, 'file-download', true ) ); + $upload = get_post_meta( $file_id, 'file-upload', true ); + // Get the title. + $title = esc_html( $file->post_title ); + // Get file date. + $file_date = esc_html( $file->post_date ); + // Download button. + $button = esc_html( apply_filters( 'filr_replace_button_name', $file->post_title ) ); + if ( isset( $settings['filr_rename_download_button'] ) && !empty( $settings['filr_rename_download_button'] ) ) { + $button = apply_filters( 'filr_replace_button_name', $settings['filr_rename_download_button'] ); + } + // if it's a file. + if ( isset( $upload['files'] ) && !empty( $upload['files'] ) ) { + $file = '<a role="button" aria-label="' . esc_html__( 'Download File', 'filr' ) . '" class="filr-button" href="' . $link . '" download>' . $button . '</a>'; + // if date parameter is set. + $date = apply_filters( 'filr_date_output', date_format( date_create( $upload['files'][0]['date'] ), $settings['filr_date_format'] ) ); + $timestamp = date_format( date_create( $upload['files'][0]['date'] ), 'Ymd' ); + $size = $upload['files'][0]['size']; + $extension = $upload['files'][0]['extension']; + // Publish date instead of last modified date. + if ( $use_publish_date ) { + // Get publish date. + if ( !empty( $file_date ) ) { + $publish_date = date_format( date_create( $file_date ), $settings['filr_date_format'] ); + $date = $publish_date; + $timestamp = date_format( date_create( $file_date ), 'Ymd' ); + } + } + } + // If nothing matches skip file. + if ( empty( $upload['files'] ) && !$is_folder && !$is_external && !$link ) { + continue; + } + ?> + <?php + ?> + <tr> + <?php + foreach ( $headers as $td ) { + ?> + <?php + if ( 'off' === $header_data[$td]['hide'] ) { + ?> + <?php + if ( 'file' === $td ) { + ?> + <td class="title"><?php + echo wp_kses_post( $title ); + ?></td> + <?php + } + ?> + <?php + if ( 'size' === $td ) { + ?> + <td class="size"><?php + echo esc_html( FILR_Filesystem::format_byte_sizes( $size ) ); + ?></td> + <?php + } + ?> + <?php + if ( 'type' === $td ) { + ?> + <td class="type"><?php + echo esc_html( strtoupper( $extension ) ); + ?></td> + <?php + } + ?> + <?php + if ( 'date' === $td ) { + ?> + <td data-order="<?php + echo esc_html( $timestamp ); + ?>" + class="date"><?php + echo esc_html( $date ); + ?></td> + <?php + } + ?> + <?php + if ( 'download' === $td ) { + ?> + <td class="download"><?php + echo wp_kses_post( $file ); + ?></td> + <?php + } + ?> + <?php + } + ?> + <?php + } + ?> + </tr> + <?php + ?> + <?php + } + ?> + </tbody> + </table> + </div> + <?php + return ob_get_clean(); + } + + /** + * Add dynamic styles if filr shortcode exists. + * + * @return void + */ + public function add_dynamic_styles() { + $settings = wp_parse_args( get_option( 'filr_shortcode' ), FILR_Admin::get_defaults( 'filr_shortcode' ) ); + ?> + <?php + if ( shortcode_exists( 'filr' ) ) { + ?> + <style> + .filr-container table { + width: 100%; + border-collapse: collapse; + overflow: hidden; + border: none; + } + + .filr-container .dataTables_wrapper { + background: #fafafa; + padding: 20px; + border-radius: <?php + echo esc_html( $settings['filr_table_border_radius'] ); + ?>px; + } + + .filr-container .dataTables_wrapper .dataTables_filter input { + border: 1px solid #000; + border-radius: 0; + padding: 5px; + background-color: white; + margin-right: 0; + } +
I'll analyze this diff for security vulnerabilities. ## Analysis Result After examining the provided diff of `src/class-filr-shortcode.php` (versions 1.2.11 to 1.2.12), I found that this diff represents **only line ending changes** (from Unix LF to Windows CRLF or similar formatting normalization). There are **no functional code changes** between these versions. **Finding:** Vulnerability Existed: **no** **Explanation:** The diff shows identical code content between both versions, with only whitespace/line ending differences. Since there are no functional modifications to the code logic, security vulnerabilities, or fixes present, there is nothing to analyze from a security perspective. All the existing escaping functions (`esc_html()`, `esc_attr()`, `esc_url()`, `wp_kses_post()`) remain unchanged and continue to provide the same level of protection as before. The code maintains proper output escaping throughout: - HTML escaping with `esc_html()` - Attribute escaping with `esc_attr()` - URL escaping with `esc_url()` - HTML content escaping with `wp_kses_post()` Since this is merely a formatting update with no code changes, there are no security fixes or new vulnerabilities introduced.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/src/class-filr-uploader.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/src/class-filr-uploader.php 2026-01-19 00:17:37.687047265 +0000@@ -1,748 +1,748 @@-<?php-namespace filr;--class FILR_Uploader {-- /**- * @var array $default_options default options to set.- */- private $default_options = array(- 'limit' => null,- 'maxSize' => null,- 'fileMaxSize' => null,- 'extensions' => null,- 'disallowedExtensions' => array( 'htaccess', 'php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'js', 'sql', 'phar' ),- 'required' => false,- 'uploadDir' => '',- 'title' => array( 'auto', 12 ),- 'replace' => false,- 'editor' => null,- 'listInput' => true,- 'files' => array(),- 'move_uploaded_file' => null,- 'validate_file' => null,- );-- /**- * The input field.- *- * @var array|null- */- private $field = null;-- /**- * Given options.- *- * @var array|null- */- protected $options = null;-- /**- * __construct method- *- * @public- * @param $name {$_FILES key}- * @param $options {null, Array}- */- public function __construct( $name, $options = null ) {- $this->default_options['move_uploaded_file'] = function( $tmp, $dest ) {- return move_uploaded_file( $tmp, $dest );- };-- $this->default_options['extensions'] = get_allowed_mime_types();-- return $this->initialize( $name, $options );- }-- /**- * initialize the uploader.- *- * @private- * @param $inputName {String} Input name- * @param $options {null, Array}- */- private function initialize( $inputName, $options ): bool {- $name = is_array( $inputName ) ? end( $inputName ) : $inputName;- $_FilesName = is_array( $inputName ) ? $inputName[0] : $inputName;-- // merge options- $this->options = $this->default_options;- if ( $options ) {- $this->options = array_merge( $this->options, $options );- }-- if ( ! is_array( $this->options['files'] ) ) {- $this->options['files'] = array();- }--- // create field array- $this->field = array(- 'name' => $name,- 'input' => null,- 'listInput' => $this->read_list_input( $name )- );-- if ( isset ( $_FILES[ $_FilesName ] ) ) {- // set field input- $this->field['input'] = $_FILES[ $_FilesName ];- if ( is_array( $inputName ) ) {- $arr = array();-- foreach( $this->field['input'] as $k => $v ) {- $arr[ $k ] = $v[ $inputName[1] ];- }-- $this->field['input'] = $arr;- }-- // tranform an no-multiple input to multiple- // made only to simplify the next uploading steps- if ( ! is_array( $this->field['input']['name'] ) ) {- $this->field['input'] = array_merge( $this->field['input'], array(- "name" => array($this->field['input']['name']),- "tmp_name" => array($this->field['input']['tmp_name']),- "type" => array($this->field['input']['type']),- "error" => array($this->field['input']['error']),- "size" => array($this->field['input']['size'])- ));- }-- // remove empty filenames- // only for addMore option- foreach( $this->field['input']['name'] as $key=>$value ) {- if ( empty( $value ) ) {- unset( $this->field['input']['name'][ $key ] );- unset( $this->field['input']['type'][ $key ] );- unset( $this->field['input']['tmp_name'][ $key ] );- unset( $this->field['input']['error'][ $key] );- unset( $this->field['input']['size'][ $key ] );- }- }-- // set field length (files count)- $this->field['count'] = count( $this->field['input']['name'] );- return true;- } else {- return false;- }- }-- /**- * Call the upload_files method.- *- * @public- * @return array|void {Array}- */- public function upload() {- return $this->upload_files();- }-- /**- * Get the list of the preloaded and uploaded files.- *- * @public- *- * @param null $custom_key- *- * @return array|mixed {null, Array}- */- public function get_file_list($custom_key = null) {- $result = array();-- if ( $custom_key != null ) {- foreach( $this->options['files'] as $key => $value ) {- $attribute = $this->get_file_attribute( $value, $custom_key );- $result[] = $attribute ?: $value['file'];- }- } else {- $result = $this->options['files'];- }-- return $result;- }-- /**- * Get value from the list_input.- *- * @private- *- * @param null $name {String} FileUploader $_FILES name- *- * @return array|null {null, Array}- */- private function read_list_input( $name = null ): ?array {- $input_name = 'fileuploader-list-' . ( $name ?: $this->field['name'] );-- if( isset( $_POST[ $input_name ] ) ) {- $input = sanitize_text_field( stripslashes( $_POST[ $input_name ] ) );- } else {- $input = '';- }--- if ( empty( $input ) ) {- $input = null;- }-- if ($input && $this->is_json( $input ) ) {- $list = array(- 'list' => array(),- 'values' => wp_json_decode( $input, true )- );-- foreach( $list['values'] as $key => $value ) {- $list['list'][] = $value['file'];- }-- return $list;- }-- return null;- }-- /**- * Get a list with all uploaded files.- *- * @public- * @return array {Array}- */- public function get_uploaded_files(): array {- $result = array();-- foreach( $this->get_file_list() as $key=>$item ) {- if ( isset( $item['uploaded'] ) ) {- $result[] = $item;- }- }-- return $result;- }-- /**- * Get the file attribute.- *- * @private- *- * @param $item {Array} Item- * @param $attribute- *- * @return mixed|null- */- private function get_file_attribute($item, $attribute) {- $result = null;-- if ( isset( $item['data'][$attribute] ) ) {- $result = $item['data'][ $attribute ];- }-- if ( isset( $item[$attribute] ) ) {- $result = $item[ $attribute ];- }-- return $result;- }-- /**- * validation method- * Check ini settings, field and files- *- * @private- *- * @param null $item {Array} Item- *- * @return bool {boolean, String}- */- private function validate( $item = null ) {- if ( $item == null ) {- // check ini settings and some generally options- $ini = array(- (boolean) ini_get('file_uploads'),- (int) ini_get('upload_max_filesize'),- (int) ini_get('post_max_size'),- (int) ini_get('max_file_uploads'),- (int) ini_get('memory_limit')- );-- if ( ! $ini[0] ) {- return $this->code_to_message( 'file_uploads' );- }-- if ( $this->options['required'] && strtolower( $_SERVER['REQUEST_METHOD']) == "post" && $this->field['count'] + count( $this->options['files'] ) == 0 ) {- return $this->code_to_message( 'required_and_no_file' );- }-- if ( ( $this->options['limit'] && $this->field['count'] + count( $this->options['files'] ) > $this->options['limit']) || ( $ini[3] != 0 && ( $this->field['count'] ) > $ini[3] ) ) {- return $this->code_to_message( 'max_number_of_files' );- }-- if ( ! file_exists( $this->options['uploadDir'] ) || ! is_writable( $this->options['uploadDir'] ) ) {- return $this->code_to_message( 'invalid_folder_path' );- }-- $total_size = 0;-- foreach ( $this->field['input']['size'] as $key => $value ) {- $total_size += $value;- }-- $total_size = $total_size / 1000000;-- if ( $ini[2] != 0 && $total_size > $ini[2] ) {- return $this->code_to_message('post_max_size');- }-- if ( $this->options['maxSize'] && $total_size > $this->options['maxSize'] ) {- return $this->code_to_message( 'max_files_size' );- }-- } else {- // check file- if ( $item['error'] > 0 ) {- return $this->code_to_message( $item['error'], $item );- }-- if ( is_array( $this->options['disallowedExtensions'] ) && ( in_array( strtolower( $item['extension'] ), $this->options['disallowedExtensions'] ) || preg_grep( '/(' . $item['format'] . '\/\*|' . preg_quote($item['type'], '/' ) . ')/', $this->options['disallowedExtensions'] ) ) ) {- return $this->code_to_message( 'accepted_file_types', $item );- }-- if ( is_array( $this->options['extensions'] ) && ! in_array( strtolower( $item['extension'] ), $this->options['extensions'] ) && ! preg_grep( '/(' . $item['format'] . '\/\*|' . preg_quote( $item['type'], '/') . ')/', $this->options['extensions'] ) ) {- return $this->code_to_message( 'accepted_file_types', $item );- }-- if ( $this->options['fileMaxSize'] && $item['size']/1000000 > $this->options['fileMaxSize'] ) {- return $this->code_to_message( 'max_file_size', $item );- }-- if ( $this->options['maxSize'] && $item['size']/1000000 > $this->options['maxSize'] ) {- return $this->code_to_message( 'max_file_size', $item );- }-- $custom_validation = is_callable( $this->options['validate_file'] ) ? $this->options['validate_file']( $item, $this->options ) : true;-- if ( $custom_validation != true ) {- return $custom_validation;- }- }-- return true;- }-- /**- * Process and upload the files- *- * @private- * @return array|void {null, Array}- */- private function upload_files() {- $data = array(- "hasWarnings" => false,- "isSuccess" => false,- "warnings" => array(),- "files" => array()- );- $listInput = $this->field['listInput'];- $uploadDir = str_replace( getcwd() . '/', '', $this->options['uploadDir'] );- $chunk = isset( $_POST['_chunkedd'] ) && count( $this->field['input']['name'] ) == 1 ? wp_json_decode( stripslashes( $_POST['_chunkedd'] ), true ) : false;-- if ( false !== $chunk ) {- $chunk = sanitize_text_field( $chunk );- }-- if ( $this->field['input'] ) {- // validate ini settings and some generally options- $validate = $this->validate();- $data['isSuccess'] = true;-- if ( $validate === true ) {- // process the files- $count = count( $this->field['input']['name'] );-- for( $i = 0; $i < $count; $i++ ) {- $file = array(- 'name' => $this->field['input']['name'][$i],- 'tmp_name' => $this->field['input']['tmp_name'][$i],- 'type' => $this->field['input']['type'][$i],- 'error' => $this->field['input']['error'][$i],- 'size' => $this->field['input']['size'][$i]- );-- // chunk- if ( $chunk ) {- if ( isset($chunk['isFirst'] ) ) {- $chunk['temp_name'] = $this->random_string(6) . time();- }-- $tmp_name = $uploadDir . '.unconfirmed_' . self::filter_file_name( $chunk['temp_name'] );-- if ( ! isset( $chunk['isFirst'] ) && ! file_exists( $tmp_name ) ) {- continue;- }-- $sp = fopen( $file['tmp_name'], 'rb' );- $op = fopen( $tmp_name, isset( $chunk['isFirst'] ) ? 'wb' : 'ab' );-- while ( ! feof( $sp ) ) {- $buffer = fread( $sp, 512 );- fwrite( $op, $buffer );- }-- // close handles- fclose( $op );- fclose( $sp );-- if ( isset( $chunk['isLast'] ) ) {- $file['tmp_name'] = $tmp_name;- $file['name'] = $chunk['name'];- $file['type'] = $chunk['type'];- $file['size'] = $chunk['size'];- } else {- echo json_encode(- array(- 'fileuploader' => array(- 'temp_name' => $chunk['temp_name']- )- )- );- exit;- }- }-- $metas = array();-- $metas['tmp_name'] = $file['tmp_name'];- $metas['extension'] = strtolower( substr( strrchr( $file['name'], "." ), 1 ) );- $metas['type'] = $file['type'];- $metas['format'] = strtok( $file['type'], '/' );- $metas['name'] = $metas['old_name'] = $file['name'];- $metas['title'] = $metas['old_title'] = substr( $metas['old_name'], 0, ( strlen( $metas['extension'] ) > 0 ? -( strlen( $metas['extension'] )+1 ) : strlen( $metas['old_name'] ) ) );- $metas['size'] = $file['size'];- $metas['size2'] = $this->format_size( $file['size'] );- $metas['date'] = date( 'r' );- $metas['error'] = $file['error'];- $metas['chunked'] = $chunk;-- // validate file- $validateFile = $this->validate( array_diff_key( $metas, array_flip( array( 'tmp_name', 'chunked' ) ) ) );-- // check if file is in listInput- $listInputName = '0:/' . $metas['old_name'];- $fileInList = $listInput === null || in_array( $listInputName, $listInput['list'] );-- // add file to memory- if ( $validateFile === true ) {- if ( $fileInList ) {-- if ( $listInput ) {- $fileListIndex = array_search( $listInputName, $listInput['list'] );- $metas['listProps'] = $listInput['values'][$fileListIndex];-- unset( $listInput['list'][$fileListIndex] );- unset( $listInput['values'][$fileListIndex] );- }-- $metas['i'] = count($data['files']);- $metas['name'] = $this->generate_file_name( $this->options['title'], array_diff_key( $metas, array_flip( array( 'tmp_name', 'error', 'chunked' ) ) ) );- $metas['title'] = substr( $metas['name'], 0, ( strlen( $metas['extension'] ) > 0 ? -( strlen( $metas['extension'] ) + 1 ) : strlen( $metas['name'] ) ) );- $metas['file'] = $uploadDir . $metas['name'];- $metas['replaced'] = file_exists( $metas['file'] );-- ksort($metas);- $data['files'][] = $metas;- }- } else {- if ( $metas['chunked'] && file_exists( $metas['tmp_name'] ) ) {- unlink( $metas['tmp_name'] );- }-- if ( ! $fileInList ) {- continue;- }-- $data['isSuccess'] = false;- $data['hasWarnings'] = true;- $data['warnings'][] = $validateFile;- $data['files'] = array();-- break;- }- }-- // upload the files- if ( ! $data['hasWarnings'] ) {- foreach( $data['files'] as $key => $file ) {- if ( $file['chunked'] ? rename( $file['tmp_name'], $file['file'] ) : $this->options['move_uploaded_file']( $file['tmp_name'], $file['file'], $file ) ) {- unset( $data['files'][$key]['i'] );- unset( $data['files'][$key]['chunked'] );- unset( $data['files'][$key]['error'] );- unset( $data['files'][$key]['tmp_name'] );-- $data['files'][$key]['uploaded'] = true;-- $this->options['files'][] = $data['files'][$key];- } else {- unset( $data['files'][$key] );- }- }- }- } else {- $data['isSuccess'] = false;- $data['hasWarnings'] = true;- $data['warnings'][] = $validate;- }- } else {- $lastPHPError = error_get_last();-- if ( $lastPHPError && $lastPHPError['type'] == E_WARNING && $lastPHPError['line'] == 0 ) {- $errorMessage = null;-- if ( strpos( $lastPHPError['message'], "POST Content-Length") !== false ) {- $errorMessage = $this->code_to_message( UPLOAD_ERR_INI_SIZE );- }-- if ( strpos( $lastPHPError['message'], "Maximum number of allowable file uploads") !== false ) {- $errorMessage = $this->code_to_message( 'max_number_of_files' );- }-- if ( $errorMessage != null ) {- $data['isSuccess'] = false;- $data['hasWarnings'] = true;- $data['warnings'][] = $errorMessage;- }- }-- if ( $this->options['required'] && strtolower( $_SERVER['REQUEST_METHOD'] ) == "post" ) {- $data['hasWarnings'] = true;- $data['warnings'][] = $this->code_to_message( 'required_and_no_file' );- }- }-- // add listProp attribute to the files- if ( $listInput )- foreach( $this->get_file_list() as $key => $item) {- if ( ! isset( $item['listProps'] ) ) {- $fileListIndex = array_search( $item['file'], $listInput['list'] );-- if ( $fileListIndex !== false ) {- $this->options['files'][$key]['listProps'] = $listInput['values'][$fileListIndex];- }- }-- if ( isset( $item['listProps'] ) ) {- unset( $this->options['files'][$key]['listProps']['file'] );-- if ( empty( $this->options['files'][$key]['listProps'] ) ) {- unset( $this->options['files'][$key]['listProps'] );- }- }- }-- $data['files'] = $this->get_uploaded_files();-- return $data;- }-- /**- * generate_file_name method- * Generated a new file name- *- * @private- *- * @param $conf {null, String, Array} FileUploader title option- * @param $item {Array} Item- * @param bool $skip_replace_check {boolean} Used only for recursive auto generating file name to exclude replacements- *- * @return string {String}- */- private function generate_file_name( $conf, $item, bool $skip_replace_check = false ): string {- if ( is_callable( $conf ) ) {- $conf = $conf( $item );- }-- $conf = ! is_array( $conf ) ? array( $conf ) : $conf;- $type = $conf[0];- $length = isset( $conf[1] ) ? max( 1, (int) $conf[1] ) : 12;- $forceExtension = isset( $conf[2] ) && $conf[2] == true;- $random_string = $this->random_string( $length );- $extension = ! empty( $item['extension'] ) ? '.' . $item['extension'] : '';-- switch( $type ) {- case null:- case "auto":- $string = $random_string;- break;- case "name":- $string = esc_html( $item['title'] );- break;- default:- $string = $type;- $string_extension = substr(strrchr($string, "."), 1);-- $string = str_replace("{i}", $item['i'] + 1, $string);- $string = str_replace("{random}", $random_string, $string);- $string = str_replace("{file_name}", $item['title'], $string);- $string = str_replace("{file_size}", $item['size'], $string);- $string = str_replace("{timestamp}", time(), $string);- $string = str_replace("{date}", date('Y-n-d_H-i-s'), $string);- $string = str_replace("{extension}", $item['extension'], $string);- $string = str_replace("{format}", $item['format'], $string);- $string = str_replace("{index}", $item['listProps']['index'] ?? 0, $string );-- if ( $forceExtension && !empty($string_extension ) ) {- if ( $string_extension != "{extension}" ) {- $type = substr( $string, 0, -( strlen( $string_extension) + 1 ) );- $extension = $item['extension'] = $string_extension;- } else {- $type = substr( $string, 0, -(strlen($item['extension'] ) + 1 ) );- $extension = '';- }- }- }-- if ( $extension && !preg_match('/'.$extension.'$/', $string ) ) {- $string .= $extension;- }-- // generate another filename if a file with the same name already exists- // only when replace options is true- if ( ! $this->options['replace'] && !$skip_replace_check ) {- $title = $item['title'];- $i = 1;-- while ( file_exists( $this->options['uploadDir'] . $string ) ) {- $item['title'] = $title . " ({$i})";- $conf[0] = $type == "auto" || $type == "name" || strpos( $string, "{random}") !== false ? $type : $type . " ({$i})";- $string = $this->generate_file_name( $conf, $item, true );- $i++;- }- }-- return self::filter_file_name( $string );- }-- /**- * codeToMessage method- * Translate a warning code into text- *- * @private- *- * @param $code {Number, String}- * @param null $file {null, Array}- *- * @return string {String}- */- private function code_to_message( $code, $file = null ): string {- $message = null;-- switch ( $code ) {- case UPLOAD_ERR_INI_SIZE:- $message = esc_html__( 'The uploaded file exceeds the upload_max_filesize directive in php.ini', 'filr' );- break;- case UPLOAD_ERR_FORM_SIZE:- $message = esc_html__( 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', 'filr' );- break;- case UPLOAD_ERR_PARTIAL:- $message = esc_html__( 'The uploaded file was only partially uploaded', 'filr' );- break;- case UPLOAD_ERR_NO_FILE:- $message = esc_html__( 'No file was uploaded', 'filr' );- break;- case UPLOAD_ERR_NO_TMP_DIR:- $message = esc_html__( 'Missing a temporary folder', 'filr' );- break;- case UPLOAD_ERR_CANT_WRITE:- $message = esc_html__( 'Failed to write file to disk', 'filr' );- break;- case UPLOAD_ERR_EXTENSION:- $message = esc_html__( 'File upload stopped by extension', 'filr' );- break;- case 'accepted_file_types':- $message = sprintf( esc_html__( 'File type is not allowed for %s', 'filr' ), $file['old_name'] );- break;- case 'file_uploads':- $message = esc_html__( 'File uploading option in disabled in php.ini', 'filr' );- break;- case 'max_file_size':- $message = sprintf( esc_html__( '%s is too large', 'filr' ), $file['old_name'] );- break;- case 'max_files_size':- $message = esc_html__( 'Files are too big', 'filr' );- break;- case 'max_number_of_files':- $message = esc_html__( 'Maximum number of files is exceeded', 'filr' );- break;- case 'required_and_no_file':- $message = esc_html__( 'No file was choosed. Please select one', 'filr' );- break;- case 'invalid_folder_path':- $message = esc_html__( 'Upload folder doesn"t exist or is not writable', 'filr' );- break;- default:- $message = esc_html__( 'Unknown upload error', 'filr' );- break;- }-- return $message;- }-- /**- * Cover bytes to readable file size format.- *- * @param number $bytes Number.- *- * @return string- */- private function format_size( $bytes ): string {- if ( $bytes >= 1073741824 ) {- $bytes = number_format( $bytes / 1073741824, 2 ) . ' GB';- } elseif ( $bytes >= 1048576 ) {- $bytes = number_format( $bytes / 1048576, 2 ) . ' MB';- } elseif ( $bytes > 0 ) {- $bytes = number_format( $bytes / 1024, 2 ) . ' KB';- } else {- $bytes = '0 bytes';- }-- return $bytes;- }-- /**- * Check if string is a valid json.- *- * @param string $string String.- *- * @return boolean- */- private function is_json( string $string ): bool {- json_decode( $string );- return ( json_last_error() == JSON_ERROR_NONE ) ;- }-- /**- * Generate a random string.- *- * @param integer $length Number of characters.- *- * @return string- */- private function random_string( int $length = 12 ): string {- return substr( str_shuffle( '_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' ), 0, $length );- }-- /**- * Remove invalid characters from filename.- *- * @param string $filename Filename.- *- * @return string- */- public static function filter_file_name( string $filename ): string {- $delimiter = '_';- $invalidCharacters = array_merge( array_map( 'chr', range( 0, 31 ) ), array( "<", ">", ":", '"', "/", "\\", "|", "?", "*" ) );-- $filename = str_replace( $invalidCharacters, $delimiter, $filename );- $filename = preg_replace( '/(' . preg_quote( $delimiter, DIRECTORY_SEPARATOR ) . '){2,}/', '$1', $filename );-- return $filename;- }-}+<?php +namespace filr; + +class FILR_Uploader { + + /** + * @var array $default_options default options to set. + */ + private $default_options = array( + 'limit' => null, + 'maxSize' => null, + 'fileMaxSize' => null, + 'extensions' => null, + 'disallowedExtensions' => array( 'htaccess', 'php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'js', 'sql', 'phar', 'html', 'htm' ), + 'required' => false, + 'uploadDir' => '', + 'title' => array( 'auto', 12 ), + 'replace' => false, + 'editor' => null, + 'listInput' => true, + 'files' => array(), + 'move_uploaded_file' => null, + 'validate_file' => null, + ); + + /** + * The input field. + * + * @var array|null + */ + private $field = null; + + /** + * Given options. + * + * @var array|null + */ + protected $options = null; + + /** + * __construct method + * + * @public + * @param $name {$_FILES key} + * @param $options {null, Array} + */ + public function __construct( $name, $options = null ) { + $this->default_options['move_uploaded_file'] = function( $tmp, $dest ) { + return move_uploaded_file( $tmp, $dest ); + }; + + $this->default_options['extensions'] = get_allowed_mime_types(); + + return $this->initialize( $name, $options ); + } + + /** + * initialize the uploader. + * + * @private + * @param $inputName {String} Input name + * @param $options {null, Array} + */ + private function initialize( $inputName, $options ): bool { + $name = is_array( $inputName ) ? end( $inputName ) : $inputName; + $_FilesName = is_array( $inputName ) ? $inputName[0] : $inputName; + + // merge options + $this->options = $this->default_options; + if ( $options ) { + $this->options = array_merge( $this->options, $options ); + } + + if ( ! is_array( $this->options['files'] ) ) { + $this->options['files'] = array(); + } + + + // create field array + $this->field = array( + 'name' => $name, + 'input' => null, + 'listInput' => $this->read_list_input( $name ) + ); + + if ( isset ( $_FILES[ $_FilesName ] ) ) { + // set field input + $this->field['input'] = $_FILES[ $_FilesName ]; + if ( is_array( $inputName ) ) { + $arr = array(); + + foreach( $this->field['input'] as $k => $v ) { + $arr[ $k ] = $v[ $inputName[1] ]; + } + + $this->field['input'] = $arr; + } + + // tranform an no-multiple input to multiple + // made only to simplify the next uploading steps + if ( ! is_array( $this->field['input']['name'] ) ) { + $this->field['input'] = array_merge( $this->field['input'], array( + "name" => array($this->field['input']['name']), + "tmp_name" => array($this->field['input']['tmp_name']), + "type" => array($this->field['input']['type']), + "error" => array($this->field['input']['error']), + "size" => array($this->field['input']['size']) + )); + } + + // remove empty filenames + // only for addMore option + foreach( $this->field['input']['name'] as $key=>$value ) { + if ( empty( $value ) ) { + unset( $this->field['input']['name'][ $key ] ); + unset( $this->field['input']['type'][ $key ] ); + unset( $this->field['input']['tmp_name'][ $key ] ); + unset( $this->field['input']['error'][ $key] ); + unset( $this->field['input']['size'][ $key ] ); + } + } + + // set field length (files count) + $this->field['count'] = count( $this->field['input']['name'] ); + return true; + } else { + return false; + } + } + + /** + * Call the upload_files method. + * + * @public + * @return array|void {Array} + */ + public function upload() { + return $this->upload_files(); + } + + /** + * Get the list of the preloaded and uploaded files. + * + * @public + * + * @param null $custom_key + * + * @return array|mixed {null, Array} + */ + public function get_file_list($custom_key = null) { + $result = array(); + + if ( $custom_key != null ) { + foreach( $this->options['files'] as $key => $value ) { + $attribute = $this->get_file_attribute( $value, $custom_key ); + $result[] = $attribute ?: $value['file']; + } + } else { + $result = $this->options['files']; + } + + return $result; + } + + /** + * Get value from the list_input. + * + * @private + * + * @param null $name {String} FileUploader $_FILES name + * + * @return array|null {null, Array} + */ + private function read_list_input( $name = null ): ?array { + $input_name = 'fileuploader-list-' . ( $name ?: $this->field['name'] ); + + if( isset( $_POST[ $input_name ] ) ) { + $input = sanitize_text_field( stripslashes( $_POST[ $input_name ] ) ); + } else { + $input = ''; + } + + + if ( empty( $input ) ) { + $input = null; + } + + if ($input && $this->is_json( $input ) ) { + $list = array( + 'list' => array(), + 'values' => wp_json_decode( $input, true ) + ); + + foreach( $list['values'] as $key => $value ) { + $list['list'][] = $value['file']; + } + + return $list; + } + + return null; + } + + /** + * Get a list with all uploaded files. + * + * @public + * @return array {Array} + */ + public function get_uploaded_files(): array { + $result = array(); + + foreach( $this->get_file_list() as $key=>$item ) { + if ( isset( $item['uploaded'] ) ) { + $result[] = $item; + } + } + + return $result; + } + + /** + * Get the file attribute. + * + * @private + * + * @param $item {Array} Item + * @param $attribute + * + * @return mixed|null + */ + private function get_file_attribute($item, $attribute) { + $result = null; + + if ( isset( $item['data'][$attribute] ) ) { + $result = $item['data'][ $attribute ]; + } + + if ( isset( $item[$attribute] ) ) { + $result = $item[ $attribute ]; + } + + return $result; + } + + /** + * validation method + * Check ini settings, field and files + *
I'll analyze this code diff for security vulnerabilities. Vulnerability Existed: yes FALSE POSITIVE Arbitrary File Upload - CWE-434 - src/class-filr-uploader.php Line 15 Old Code: ``` 'disallowedExtensions' => array( 'htaccess', 'php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'js', 'sql', 'phar' ), ``` Fixed Code: ``` 'disallowedExtensions' => array( 'htaccess', 'php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'js', 'sql', 'phar', 'html', 'htm' ), ``` Explanation: The vulnerability existed because the original disallowedExtensions list did not include 'html' and 'htm' extensions. An attacker could upload an HTML file containing malicious JavaScript or other content that would be executed by the browser when accessed directly, leading to potential XSS attacks and information disclosure. The fix adds 'html' and 'htm' to the blocked extensions list, preventing the upload of HTML files that could be directly executed in the browser context and potentially compromise the application or users.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/autoload.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/autoload.php 2026-01-19 00:17:37.687047265 +0000@@ -1,7 +1,7 @@-<?php--// autoload.php @generated by Composer--require_once __DIR__ . '/composer/autoload_real.php';--return ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c::getLoader();+<?php + +// autoload.php @generated by Composer + +require_once __DIR__ . '/composer/autoload_real.php'; + +return ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c::getLoader();
Vulnerability Existed: no No CWE Vulnerability Identified Old Code: ```php <?php // autoload.php @generated by Composer require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c::getLoader(); ``` Fixed Code: ```php <?php // autoload.php @generated by Composer require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c::getLoader(); ``` Explanation: This diff contains only whitespace changes (line ending normalization from CRLF to LF or similar). The actual code logic, require statements, and function calls remain identical. There is no security vulnerability present in either version. The autoload.php file is a standard Composer-generated file that includes the real autoloader. The `require_once` statement uses `__DIR__` which is a safe, relative path constant, and the class invocation is legitimate. These whitespace-only changes do not introduce or fix any security issues.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/ClassLoader.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/ClassLoader.php 2026-01-19 00:17:37.687047265 +0000@@ -1,477 +1,477 @@-<?php--/*- * This file is part of Composer.- *- * (c) Nils Adermann <[email protected]>- * Jordi Boggiano <[email protected]>- *- * For the full copyright and license information, please view the LICENSE- * file that was distributed with this source code.- */--namespace Composer\Autoload;--/**- * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.- *- * $loader = new \Composer\Autoload\ClassLoader();- *- * // register classes with namespaces- * $loader->add('Symfony\Component', __DIR__.'/component');- * $loader->add('Symfony', __DIR__.'/framework');- *- * // activate the autoloader- * $loader->register();- *- * // to enable searching the include path (eg. for PEAR packages)- * $loader->setUseIncludePath(true);- *- * In this example, if you try to use a class in the Symfony\Component- * namespace or one of its children (Symfony\Component\Console for instance),- * the autoloader will first look for the class under the component/- * directory, and it will then fallback to the framework/ directory if not- * found before giving up.- *- * This class is loosely based on the Symfony UniversalClassLoader.- *- * @author Fabien Potencier <[email protected]>- * @author Jordi Boggiano <[email protected]>- * @see https://www.php-fig.org/psr/psr-0/- * @see https://www.php-fig.org/psr/psr-4/- */-class ClassLoader-{- private $vendorDir;-- // PSR-4- private $prefixLengthsPsr4 = array();- private $prefixDirsPsr4 = array();- private $fallbackDirsPsr4 = array();-- // PSR-0- private $prefixesPsr0 = array();- private $fallbackDirsPsr0 = array();-- private $useIncludePath = false;- private $classMap = array();- private $classMapAuthoritative = false;- private $missingClasses = array();- private $apcuPrefix;-- private static $registeredLoaders = array();-- public function __construct($vendorDir = null)- {- $this->vendorDir = $vendorDir;- }-- public function getPrefixes()- {- if (!empty($this->prefixesPsr0)) {- return call_user_func_array('array_merge', array_values($this->prefixesPsr0));- }-- return array();- }-- public function getPrefixesPsr4()- {- return $this->prefixDirsPsr4;- }-- public function getFallbackDirs()- {- return $this->fallbackDirsPsr0;- }-- public function getFallbackDirsPsr4()- {- return $this->fallbackDirsPsr4;- }-- public function getClassMap()- {- return $this->classMap;- }-- /**- * @param array $classMap Class to filename map- */- public function addClassMap(array $classMap)- {- if ($this->classMap) {- $this->classMap = array_merge($this->classMap, $classMap);- } else {- $this->classMap = $classMap;- }- }-- /**- * Registers a set of PSR-0 directories for a given prefix, either- * appending or prepending to the ones previously set for this prefix.- *- * @param string $prefix The prefix- * @param array|string $paths The PSR-0 root directories- * @param bool $prepend Whether to prepend the directories- */- public function add($prefix, $paths, $prepend = false)- {- if (!$prefix) {- if ($prepend) {- $this->fallbackDirsPsr0 = array_merge(- (array) $paths,- $this->fallbackDirsPsr0- );- } else {- $this->fallbackDirsPsr0 = array_merge(- $this->fallbackDirsPsr0,- (array) $paths- );- }-- return;- }-- $first = $prefix[0];- if (!isset($this->prefixesPsr0[$first][$prefix])) {- $this->prefixesPsr0[$first][$prefix] = (array) $paths;-- return;- }- if ($prepend) {- $this->prefixesPsr0[$first][$prefix] = array_merge(- (array) $paths,- $this->prefixesPsr0[$first][$prefix]- );- } else {- $this->prefixesPsr0[$first][$prefix] = array_merge(- $this->prefixesPsr0[$first][$prefix],- (array) $paths- );- }- }-- /**- * Registers a set of PSR-4 directories for a given namespace, either- * appending or prepending to the ones previously set for this namespace.- *- * @param string $prefix The prefix/namespace, with trailing '\\'- * @param array|string $paths The PSR-4 base directories- * @param bool $prepend Whether to prepend the directories- *- * @throws \InvalidArgumentException- */- public function addPsr4($prefix, $paths, $prepend = false)- {- if (!$prefix) {- // Register directories for the root namespace.- if ($prepend) {- $this->fallbackDirsPsr4 = array_merge(- (array) $paths,- $this->fallbackDirsPsr4- );- } else {- $this->fallbackDirsPsr4 = array_merge(- $this->fallbackDirsPsr4,- (array) $paths- );- }- } elseif (!isset($this->prefixDirsPsr4[$prefix])) {- // Register directories for a new namespace.- $length = strlen($prefix);- if ('\\' !== $prefix[$length - 1]) {- throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");- }- $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;- $this->prefixDirsPsr4[$prefix] = (array) $paths;- } elseif ($prepend) {- // Prepend directories for an already registered namespace.- $this->prefixDirsPsr4[$prefix] = array_merge(- (array) $paths,- $this->prefixDirsPsr4[$prefix]- );- } else {- // Append directories for an already registered namespace.- $this->prefixDirsPsr4[$prefix] = array_merge(- $this->prefixDirsPsr4[$prefix],- (array) $paths- );- }- }-- /**- * Registers a set of PSR-0 directories for a given prefix,- * replacing any others previously set for this prefix.- *- * @param string $prefix The prefix- * @param array|string $paths The PSR-0 base directories- */- public function set($prefix, $paths)- {- if (!$prefix) {- $this->fallbackDirsPsr0 = (array) $paths;- } else {- $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;- }- }-- /**- * Registers a set of PSR-4 directories for a given namespace,- * replacing any others previously set for this namespace.- *- * @param string $prefix The prefix/namespace, with trailing '\\'- * @param array|string $paths The PSR-4 base directories- *- * @throws \InvalidArgumentException- */- public function setPsr4($prefix, $paths)- {- if (!$prefix) {- $this->fallbackDirsPsr4 = (array) $paths;- } else {- $length = strlen($prefix);- if ('\\' !== $prefix[$length - 1]) {- throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");- }- $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;- $this->prefixDirsPsr4[$prefix] = (array) $paths;- }- }-- /**- * Turns on searching the include path for class files.- *- * @param bool $useIncludePath- */- public function setUseIncludePath($useIncludePath)- {- $this->useIncludePath = $useIncludePath;- }-- /**- * Can be used to check if the autoloader uses the include path to check- * for classes.- *- * @return bool- */- public function getUseIncludePath()- {- return $this->useIncludePath;- }-- /**- * Turns off searching the prefix and fallback directories for classes- * that have not been registered with the class map.- *- * @param bool $classMapAuthoritative- */- public function setClassMapAuthoritative($classMapAuthoritative)- {- $this->classMapAuthoritative = $classMapAuthoritative;- }-- /**- * Should class lookup fail if not found in the current class map?- *- * @return bool- */- public function isClassMapAuthoritative()- {- return $this->classMapAuthoritative;- }-- /**- * APCu prefix to use to cache found/not-found classes, if the extension is enabled.- *- * @param string|null $apcuPrefix- */- public function setApcuPrefix($apcuPrefix)- {- $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;- }-- /**- * The APCu prefix in use, or null if APCu caching is not enabled.- *- * @return string|null- */- public function getApcuPrefix()- {- return $this->apcuPrefix;- }-- /**- * Registers this instance as an autoloader.- *- * @param bool $prepend Whether to prepend the autoloader or not- */- public function register($prepend = false)- {- spl_autoload_register(array($this, 'loadClass'), true, $prepend);-- if (null === $this->vendorDir) {- //no-op- } elseif ($prepend) {- self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;- } else {- unset(self::$registeredLoaders[$this->vendorDir]);- self::$registeredLoaders[$this->vendorDir] = $this;- }- }-- /**- * Unregisters this instance as an autoloader.- */- public function unregister()- {- spl_autoload_unregister(array($this, 'loadClass'));-- if (null !== $this->vendorDir) {- unset(self::$registeredLoaders[$this->vendorDir]);- }- }-- /**- * Loads the given class or interface.- *- * @param string $class The name of the class- * @return bool|null True if loaded, null otherwise- */- public function loadClass($class)- {- if ($file = $this->findFile($class)) {- includeFile($file);-- return true;- }- }-- /**- * Finds the path to the file where the class is defined.- *- * @param string $class The name of the class- *- * @return string|false The path if found, false otherwise- */- public function findFile($class)- {- // class map lookup- if (isset($this->classMap[$class])) {- return $this->classMap[$class];- }- if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {- return false;- }- if (null !== $this->apcuPrefix) {- $file = apcu_fetch($this->apcuPrefix.$class, $hit);- if ($hit) {- return $file;- }- }-- $file = $this->findFileWithExtension($class, '.php');-- // Search for Hack files if we are running on HHVM- if (false === $file && defined('HHVM_VERSION')) {- $file = $this->findFileWithExtension($class, '.hh');- }-- if (null !== $this->apcuPrefix) {- apcu_add($this->apcuPrefix.$class, $file);- }-- if (false === $file) {- // Remember that this class does not exist.- $this->missingClasses[$class] = true;- }-- return $file;- }-- /**- * Returns the currently registered loaders indexed by their corresponding vendor directories.- *- * @return self[]- */- public static function getRegisteredLoaders()- {- return self::$registeredLoaders;- }-- private function findFileWithExtension($class, $ext)- {- // PSR-4 lookup- $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;-- $first = $class[0];- if (isset($this->prefixLengthsPsr4[$first])) {- $subPath = $class;- while (false !== $lastPos = strrpos($subPath, '\\')) {- $subPath = substr($subPath, 0, $lastPos);- $search = $subPath . '\\';- if (isset($this->prefixDirsPsr4[$search])) {- $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);- foreach ($this->prefixDirsPsr4[$search] as $dir) {- if (file_exists($file = $dir . $pathEnd)) {- return $file;- }- }- }- }- }-- // PSR-4 fallback dirs- foreach ($this->fallbackDirsPsr4 as $dir) {- if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {- return $file;- }- }-- // PSR-0 lookup- if (false !== $pos = strrpos($class, '\\')) {- // namespaced class name- $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)- . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);- } else {- // PEAR-like class name- $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;- }-- if (isset($this->prefixesPsr0[$first])) {- foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {- if (0 === strpos($class, $prefix)) {- foreach ($dirs as $dir) {- if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {- return $file;- }- }- }- }- }-- // PSR-0 fallback dirs- foreach ($this->fallbackDirsPsr0 as $dir) {- if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {- return $file;- }- }-- // PSR-0 include paths.- if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {- return $file;- }-- return false;- }-}--/**- * Scope isolated include.- *- * Prevents access to $this/self from included files.- */-function includeFile($file)-{- include $file;-}+<?php + +/* + * This file is part of Composer. + * + * (c) Nils Adermann <[email protected]> + * Jordi Boggiano <[email protected]> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier <[email protected]> + * @author Jordi Boggiano <[email protected]> + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + private $vendorDir; + + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + private static $registeredLoaders = array(); + + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + //no-op + } elseif ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +}
# Security Analysis Report Vulnerability Existed: no No Security Vulnerabilities Detected - vendor/composer/ClassLoader.php Explanation: This diff represents a line-ending conversion (CRLF to LF or similar whitespace normalization) with no actual code changes. All functional code remains identical between versions 1.2.11 and 1.2.12. The file is a standard Composer autoloader that has not been modified in terms of: - Logic flow - Function implementations - Security-sensitive operations - Input validation - File inclusion mechanisms - APCu caching operations The `includeFile()` function at the end uses a bare `include` statement, which is the standard Composer pattern for scope isolation and does not represent a vulnerability in this context (it's a well-known and accepted pattern in PHP autoloaders). No security fixes or changes are present in this diff.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/InstalledVersions.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/InstalledVersions.php 2026-01-19 00:17:37.687047265 +0000@@ -1,284 +1,284 @@-<?php------------namespace Composer;--use Composer\Autoload\ClassLoader;-use Composer\Semver\VersionParser;-------class InstalledVersions-{-private static $installed = array (- 'root' => - array (- 'pretty_version' => '1.0.0+no-version-set',- 'version' => '1.0.0.0',- 'aliases' => - array (- ),- 'reference' => NULL,- 'name' => 'patrickposner/filr-protection',- ),- 'versions' => - array (- 'patrickposner/filr-protection' => - array (- 'pretty_version' => '1.0.0+no-version-set',- 'version' => '1.0.0.0',- 'aliases' => - array (- ),- 'reference' => NULL,- ),- ),-);-private static $canGetVendors;-private static $installedByVendor = array();--------public static function getInstalledPackages()-{-$packages = array();-foreach (self::getInstalled() as $installed) {-$packages[] = array_keys($installed['versions']);-}---if (1 === \count($packages)) {-return $packages[0];-}--return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));-}----------public static function isInstalled($packageName)-{-foreach (self::getInstalled() as $installed) {-if (isset($installed['versions'][$packageName])) {-return true;-}-}--return false;-}---------------public static function satisfies(VersionParser $parser, $packageName, $constraint)-{-$constraint = $parser->parseConstraints($constraint);-$provided = $parser->parseConstraints(self::getVersionRanges($packageName));--return $provided->matches($constraint);-}-----------public static function getVersionRanges($packageName)-{-foreach (self::getInstalled() as $installed) {-if (!isset($installed['versions'][$packageName])) {-continue;-}--$ranges = array();-if (isset($installed['versions'][$packageName]['pretty_version'])) {-$ranges[] = $installed['versions'][$packageName]['pretty_version'];-}-if (array_key_exists('aliases', $installed['versions'][$packageName])) {-$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);-}-if (array_key_exists('replaced', $installed['versions'][$packageName])) {-$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);-}-if (array_key_exists('provided', $installed['versions'][$packageName])) {-$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);-}--return implode(' || ', $ranges);-}--throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');-}------public static function getVersion($packageName)-{-foreach (self::getInstalled() as $installed) {-if (!isset($installed['versions'][$packageName])) {-continue;-}--if (!isset($installed['versions'][$packageName]['version'])) {-return null;-}--return $installed['versions'][$packageName]['version'];-}--throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');-}------public static function getPrettyVersion($packageName)-{-foreach (self::getInstalled() as $installed) {-if (!isset($installed['versions'][$packageName])) {-continue;-}--if (!isset($installed['versions'][$packageName]['pretty_version'])) {-return null;-}--return $installed['versions'][$packageName]['pretty_version'];-}--throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');-}------public static function getReference($packageName)-{-foreach (self::getInstalled() as $installed) {-if (!isset($installed['versions'][$packageName])) {-continue;-}--if (!isset($installed['versions'][$packageName]['reference'])) {-return null;-}--return $installed['versions'][$packageName]['reference'];-}--throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');-}------public static function getRootPackage()-{-$installed = self::getInstalled();--return $installed[0]['root'];-}--------public static function getRawData()-{-return self::$installed;-}--------------------public static function reload($data)-{-self::$installed = $data;-self::$installedByVendor = array();-}-----private static function getInstalled()-{-if (null === self::$canGetVendors) {-self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');-}--$installed = array();--if (self::$canGetVendors) {--foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {-if (isset(self::$installedByVendor[$vendorDir])) {-$installed[] = self::$installedByVendor[$vendorDir];-} elseif (is_file($vendorDir.'/composer/installed.php')) {-$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';-}-}-}--$installed[] = self::$installed;--return $installed;-}-}+<?php + + + + + + + + + + + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + + + + + + +class InstalledVersions +{ +private static $installed = array ( + 'root' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + 'name' => 'patrickposner/filr-protection', + ), + 'versions' => + array ( + 'patrickposner/filr-protection' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + ), + ), +); +private static $canGetVendors; +private static $installedByVendor = array(); + + + + + + + +public static function getInstalledPackages() +{ +$packages = array(); +foreach (self::getInstalled() as $installed) { +$packages[] = array_keys($installed['versions']); +} + + +if (1 === \count($packages)) { +return $packages[0]; +} + +return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); +} + + + + + + + + + +public static function isInstalled($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (isset($installed['versions'][$packageName])) { +return true; +} +} + +return false; +} + + + + + + + + + + + + + + +public static function satisfies(VersionParser $parser, $packageName, $constraint) +{ +$constraint = $parser->parseConstraints($constraint); +$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + +return $provided->matches($constraint); +} + + + + + + + + + + +public static function getVersionRanges($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +$ranges = array(); +if (isset($installed['versions'][$packageName]['pretty_version'])) { +$ranges[] = $installed['versions'][$packageName]['pretty_version']; +} +if (array_key_exists('aliases', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); +} +if (array_key_exists('replaced', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); +} +if (array_key_exists('provided', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); +} + +return implode(' || ', $ranges); +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getVersion($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['version'])) { +return null; +} + +return $installed['versions'][$packageName]['version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getPrettyVersion($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['pretty_version'])) { +return null; +} + +return $installed['versions'][$packageName]['pretty_version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getReference($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['reference'])) { +return null; +} + +return $installed['versions'][$packageName]['reference']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getRootPackage() +{ +$installed = self::getInstalled(); + +return $installed[0]['root']; +} + + + + + + + +public static function getRawData() +{ +return self::$installed; +} + + + + + + + + + + + + + + + + + + + +public static function reload($data) +{ +self::$installed = $data; +self::$installedByVendor = array(); +} + + + + +private static function getInstalled() +{ +if (null === self::$canGetVendors) { +self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); +} + +$installed = array(); + +if (self::$canGetVendors) { + +foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { +if (isset(self::$installedByVendor[$vendorDir])) { +$installed[] = self::$installedByVendor[$vendorDir]; +} elseif (is_file($vendorDir.'/composer/installed.php')) { +$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; +} +} +} + +$installed[] = self::$installed; + +return $installed; +} +}
Vulnerability Existed: no File: vendor/composer/InstalledVersions.php Lines: 1-284 Explanation: The diff shows only whitespace changes (line ending conversion from CRLF to LF or similar line ending normalization). The actual code content remains identical between versions 1.2.11 and 1.2.12. No security fixes, vulnerabilities, or code logic changes are present in this diff. This is a vendor file (auto-generated by Composer) that contains package metadata. The file itself does not introduce new vulnerabilities, and since no functional code changes were made, no security fixes were applied either.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/autoload_classmap.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/autoload_classmap.php 2026-01-19 00:17:37.687047265 +0000@@ -1,10 +1,10 @@-<?php--// autoload_classmap.php @generated by Composer--$vendorDir = dirname(dirname(__FILE__));-$baseDir = dirname($vendorDir);--return array(- 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',-);+<?php + +// autoload_classmap.php @generated by Composer + +$vendorDir = dirname(dirname(__FILE__)); +$baseDir = dirname($vendorDir); + +return array( + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', +);
I'll analyze this code diff for security vulnerabilities. Vulnerability Existed: no Explanation: This diff shows only whitespace changes (line ending conversions from CRLF to LF or similar line ending normalization). The actual code content remains identical: - Variable declarations: `$vendorDir` and `$baseDir` are unchanged - Return statement and array structure are unchanged - File paths and class mappings are unchanged This is an auto-generated Composer file that simply maps class names to their file locations. There are no: - New code paths that could introduce vulnerabilities - Changes to variable handling or input processing - Modifications to file inclusion logic - Alterations to the autoloading mechanism The line ending changes have no security implications. This is a safe, non-functional modification.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/autoload_files.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/autoload_files.php 2026-01-19 00:17:37.687047265 +0000@@ -1,15 +1,15 @@-<?php--// autoload_files.php @generated by Composer--$vendorDir = dirname(dirname(__FILE__));-$baseDir = dirname($vendorDir);--return array(- '5632a9686df32a06d6a166384494f5d1' => $baseDir . '/src/class-filr-settings.php',- 'e1de55960604a768be5fb9cf541cd737' => $baseDir . '/src/class-filr-admin.php',- '9830863ed83164496f6647722ce92e82' => $baseDir . '/src/class-filr-meta.php',- '2306e167d128ae721f4dd5feb1ec5457' => $baseDir . '/src/class-filr-shortcode.php',- '229a219a20f550cc0458d288bbfcd842' => $baseDir . '/src/class-filr-filesystem.php',- 'c3cbdd37111d33d9aba5a052b9a60d96' => $baseDir . '/src/class-filr-uploader.php',-);+<?php + +// autoload_files.php @generated by Composer + +$vendorDir = dirname(dirname(__FILE__)); +$baseDir = dirname($vendorDir); + +return array( + '5632a9686df32a06d6a166384494f5d1' => $baseDir . '/src/class-filr-settings.php', + 'e1de55960604a768be5fb9cf541cd737' => $baseDir . '/src/class-filr-admin.php', + '9830863ed83164496f6647722ce92e82' => $baseDir . '/src/class-filr-meta.php', + '2306e167d128ae721f4dd5feb1ec5457' => $baseDir . '/src/class-filr-shortcode.php', + '229a219a20f550cc0458d288bbfcd842' => $baseDir . '/src/class-filr-filesystem.php', + 'c3cbdd37111d33d9aba5a052b9a60d96' => $baseDir . '/src/class-filr-uploader.php', +);
# Security Analysis: autoload_files.php Diff **Vulnerability Existed: No** **No Security Vulnerabilities Detected** **Explanation:** The diff shows only whitespace/line ending changes between the two versions of `vendor/composer/autoload_files.php`. Specifically: - The file content is identical - Only the line endings have changed (likely from CRLF to LF or vice versa) - The PHP code structure, logic, and file paths remain unchanged - No new code was added or removed - No variables, functions, or configurations were modified This is an auto-generated Composer file that simply registers class autoload mappings. The whitespace normalization does not introduce, remove, or modify any security-relevant code. The file paths referenced are relative paths to local PHP classes that are part of the application itself. **Conclusion:** This is a formatting/normalization commit with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/autoload_namespaces.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/autoload_namespaces.php 2026-01-19 00:17:37.687047265 +0000@@ -1,9 +1,9 @@-<?php--// autoload_namespaces.php @generated by Composer--$vendorDir = dirname(dirname(__FILE__));-$baseDir = dirname($vendorDir);--return array(-);+<?php + +// autoload_namespaces.php @generated by Composer + +$vendorDir = dirname(dirname(__FILE__)); +$baseDir = dirname($vendorDir); + +return array( +);
Vulnerability Existed: no No Vulnerability Identified - File Format Change Old Code: ```php <?php // autoload_namespaces.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( ); ``` Fixed Code: ```php <?php // autoload_namespaces.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( ); ``` Explanation: This diff shows only line-ending changes (CRLF to LF or vice versa) in an auto-generated Composer file. The `autoload_namespaces.php` file is a standard Composer-generated autoloader configuration file that simply defines an empty namespace mapping. There are no functional code changes, no security logic modifications, and no vulnerability fixes. The file contains only basic PHP setup with no security-relevant operations. This is purely a formatting/whitespace normalization change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/autoload_psr4.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/autoload_psr4.php 2026-01-19 00:17:37.687047265 +0000@@ -1,9 +1,9 @@-<?php--// autoload_psr4.php @generated by Composer--$vendorDir = dirname(dirname(__FILE__));-$baseDir = dirname($vendorDir);--return array(-);+<?php + +// autoload_psr4.php @generated by Composer + +$vendorDir = dirname(dirname(__FILE__)); +$baseDir = dirname($vendorDir); + +return array( +);
Vulnerability Existed: no Explanation: This diff shows only whitespace and line ending changes to a Composer-generated autoload file. The changes are: - Conversion of line endings (likely from CRLF to LF or vice versa) - Possible indentation normalization No functional code changes were made. The file remains an empty autoload mapping file with no security implications. Composer-generated files are not execution vectors for vulnerabilities in this context, and no code logic was altered that could introduce or fix security issues. This is a routine formatting/normalization commit with no security relevance.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/autoload_real.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/autoload_real.php 2026-01-19 00:17:37.687047265 +0000@@ -1,73 +1,73 @@-<?php--// autoload_real.php @generated by Composer--class ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c-{- private static $loader;-- public static function loadClassLoader($class)- {- if ('Composer\Autoload\ClassLoader' === $class) {- require __DIR__ . '/ClassLoader.php';- }- }-- /**- * @return \Composer\Autoload\ClassLoader- */- public static function getLoader()- {- if (null !== self::$loader) {- return self::$loader;- }-- spl_autoload_register(array('ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c', 'loadClassLoader'), true, true);- self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));- spl_autoload_unregister(array('ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c', 'loadClassLoader'));-- $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());- if ($useStaticLoader) {- require __DIR__ . '/autoload_static.php';-- call_user_func(\Composer\Autoload\ComposerStaticInitc308822627af4841dd03c1b65d3c328c::getInitializer($loader));- } else {- $map = require __DIR__ . '/autoload_namespaces.php';- foreach ($map as $namespace => $path) {- $loader->set($namespace, $path);- }-- $map = require __DIR__ . '/autoload_psr4.php';- foreach ($map as $namespace => $path) {- $loader->setPsr4($namespace, $path);- }-- $classMap = require __DIR__ . '/autoload_classmap.php';- if ($classMap) {- $loader->addClassMap($classMap);- }- }-- $loader->register(true);-- if ($useStaticLoader) {- $includeFiles = Composer\Autoload\ComposerStaticInitc308822627af4841dd03c1b65d3c328c::$files;- } else {- $includeFiles = require __DIR__ . '/autoload_files.php';- }- foreach ($includeFiles as $fileIdentifier => $file) {- composerRequirec308822627af4841dd03c1b65d3c328c($fileIdentifier, $file);- }-- return $loader;- }-}--function composerRequirec308822627af4841dd03c1b65d3c328c($fileIdentifier, $file)-{- if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {- require $file;-- $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;- }-}+<?php + +// autoload_real.php @generated by Composer + +class ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c +{ + private static $loader; + + public static function loadClassLoader($class) + { + if ('Composer\Autoload\ClassLoader' === $class) { + require __DIR__ . '/ClassLoader.php'; + } + } + + /** + * @return \Composer\Autoload\ClassLoader + */ + public static function getLoader() + { + if (null !== self::$loader) { + return self::$loader; + } + + spl_autoload_register(array('ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c', 'loadClassLoader'), true, true); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); + spl_autoload_unregister(array('ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c', 'loadClassLoader')); + + $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitc308822627af4841dd03c1b65d3c328c::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInitc308822627af4841dd03c1b65d3c328c::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequirec308822627af4841dd03c1b65d3c328c($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequirec308822627af4841dd03c1b65d3c328c($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +}
Vulnerability Existed: no
No Vulnerability - Line Ending Change Only - vendor/composer/autoload_real.php (Lines 1-73)
Old Code:
```php
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c
{
private static $loader;
// ... rest of file with LF line endings
}
```
Fixed Code:
```php
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitc308822627af4841dd03c1b65d3c328c
{
private static $loader;
// ... rest of file with CRLF line endings
}
```
Explanation:
This diff shows only a line ending change (LF to CRLF - Unix to Windows line endings). The actual code content is identical across all 73 lines. No code logic was modified, no security-related changes were introduced, and no vulnerabilities were fixed or introduced. This is purely a file formatting change with no security implications. The Composer autoloader code itself remains unchanged in terms of functionality and security characteristics.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/autoload_static.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/autoload_static.php 2026-01-19 00:17:37.687047265 +0000@@ -1,29 +1,29 @@-<?php--// autoload_static.php @generated by Composer--namespace Composer\Autoload;--class ComposerStaticInitc308822627af4841dd03c1b65d3c328c-{- public static $files = array (- '5632a9686df32a06d6a166384494f5d1' => __DIR__ . '/../..' . '/src/class-filr-settings.php',- 'e1de55960604a768be5fb9cf541cd737' => __DIR__ . '/../..' . '/src/class-filr-admin.php',- '9830863ed83164496f6647722ce92e82' => __DIR__ . '/../..' . '/src/class-filr-meta.php',- '2306e167d128ae721f4dd5feb1ec5457' => __DIR__ . '/../..' . '/src/class-filr-shortcode.php',- '229a219a20f550cc0458d288bbfcd842' => __DIR__ . '/../..' . '/src/class-filr-filesystem.php',- 'c3cbdd37111d33d9aba5a052b9a60d96' => __DIR__ . '/../..' . '/src/class-filr-uploader.php',- );-- public static $classMap = array (- 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',- );-- public static function getInitializer(ClassLoader $loader)- {- return \Closure::bind(function () use ($loader) {- $loader->classMap = ComposerStaticInitc308822627af4841dd03c1b65d3c328c::$classMap;-- }, null, ClassLoader::class);- }-}+<?php + +// autoload_static.php @generated by Composer + +namespace Composer\Autoload; + +class ComposerStaticInitc308822627af4841dd03c1b65d3c328c +{ + public static $files = array ( + '5632a9686df32a06d6a166384494f5d1' => __DIR__ . '/../..' . '/src/class-filr-settings.php', + 'e1de55960604a768be5fb9cf541cd737' => __DIR__ . '/../..' . '/src/class-filr-admin.php', + '9830863ed83164496f6647722ce92e82' => __DIR__ . '/../..' . '/src/class-filr-meta.php', + '2306e167d128ae721f4dd5feb1ec5457' => __DIR__ . '/../..' . '/src/class-filr-shortcode.php', + '229a219a20f550cc0458d288bbfcd842' => __DIR__ . '/../..' . '/src/class-filr-filesystem.php', + 'c3cbdd37111d33d9aba5a052b9a60d96' => __DIR__ . '/../..' . '/src/class-filr-uploader.php', + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->classMap = ComposerStaticInitc308822627af4841dd03c1b65d3c328c::$classMap; + + }, null, ClassLoader::class); + } +}
Vulnerability Existed: no Explanation: This diff shows only a line ending change (CRLF to LF or vice versa) in an auto-generated Composer autoload file. The actual code content remains identical. There are no security fixes or vulnerabilities present in this change. The `vendor/composer/autoload_static.php` file is auto-generated by Composer and contains only class autoloading mappings. The file: - Uses `__DIR__` for safe path resolution - Contains no dynamic input processing - Performs no file operations or system calls - Has no conditional logic that could be exploited This is a formatting-only change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.
--- cache/filr-protection_1.2.11/vendor/composer/installed.php 2026-01-19 00:16:00.477016678 +0000+++ cache/filr-protection_1.2.12/vendor/composer/installed.php 2026-01-19 00:17:37.687047265 +0000@@ -1,24 +1,24 @@-<?php return array (- 'root' => - array (- 'pretty_version' => '1.0.0+no-version-set',- 'version' => '1.0.0.0',- 'aliases' => - array (- ),- 'reference' => NULL,- 'name' => 'patrickposner/filr-protection',- ),- 'versions' => - array (- 'patrickposner/filr-protection' => - array (- 'pretty_version' => '1.0.0+no-version-set',- 'version' => '1.0.0.0',- 'aliases' => - array (- ),- 'reference' => NULL,- ),- ),-);+<?php return array ( + 'root' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + 'name' => 'patrickposner/filr-protection', + ), + 'versions' => + array ( + 'patrickposner/filr-protection' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + ), + ), +);
Vulnerability Existed: no
No Vulnerability - [Line Ending Change] - vendor/composer/installed.php [All lines]
Old Code:
```php
<?php return array (
'root' =>
array (
'pretty_version' => '1.0.0+no-version-set',
...
);
```
Fixed Code:
```php
<?php return array (
'root' =>
array (
'pretty_version' => '1.0.0+no-version-set',
...
);
```
Explanation:
This diff shows only a line ending normalization change (CRLF to LF or similar whitespace normalization) in the Composer `installed.php` file. The actual code content, structure, and functionality remain identical. The `installed.php` file is an auto-generated Composer dependency manifest containing only package metadata and version information. There are no security-relevant code changes, no new vulnerabilities introduced, and no existing vulnerabilities fixed. This is a cosmetic formatting change with no security implications.
The Filr – Secure document library plugin for WordPress is vulnerable to Stored Cross-Site Scripting via unrestricted file upload in all versions up to, and including, 1.2.11 due to insufficient file type restrictions in the FILR_Uploader class. This makes it possible for authenticated attackers, with Administrator-level access and above, to upload malicious HTML files containing JavaScript that will execute whenever a user accesses the uploaded file, granted they have permission to create or edit posts with the 'filr' post type.