| @@ -5279,16 +5279,32 @@ | ||
| 5279 | 5279 | |
| 5280 | 5280 | /** |
| 5281 | 5281 | * Add a file to the ignored list |
| 5282 | 5282 | * |
| 5283 | + * The path is stored exactly as it comes: the callers are the AJAX | |
| 5284 | + * handlers, which have already read it and checked it against the shared | |
| 5285 | + * files and Vigilant's own, and the scan compares the stored strings with | |
| 5286 | + * the paths it finds one by one (in_array(), strict). This used to run | |
| 5287 | + * sanitize_text_field() over it, which deletes every %XX octet and collapses | |
| 5288 | + * repeated spaces, so the entry never matched the file it was made for | |
| 5289 | + * (measured on 1 oct 2026 against 3.0.1). Anything that is not a plain | |
| 5290 | + * string, is empty or carries tags is not a path and is refused. That guards | |
| 5291 | + * a direct caller: the AJAX handlers read the path with wp_strip_all_tags() | |
| 5292 | + * first, which shortens a name with a stray < instead of handing it over | |
| 5293 | + * intact (see ajax_ignore_file()). | |
| 5294 | + * | |
| 5283 | 5295 | * @param string $file_path Relative file path to ignore. |
| 5284 | 5296 | * @return bool |
| 5285 | 5297 | */ |
| 5286 | 5298 | public function ignore_file( $file_path ) { |
| 5299 | + if ( ! is_string( $file_path ) || '' === $file_path || wp_strip_all_tags( $file_path ) !== $file_path ) { | |
| 5300 | + return false; | |
| 5301 | + } | |
| 5302 | + | |
| 5287 | 5303 | $ignored = get_option( 'vigilante_ignored_files', array() ); |
| 5288 | 5304 | |
| 5289 | 5305 | if ( ! in_array( $file_path, $ignored, true ) ) { |
| 5290 | - $ignored[] = sanitize_text_field( $file_path ); | |
| 5306 | + $ignored[] = $file_path; | |
| 5291 | 5307 | return update_option( 'vigilante_ignored_files', $ignored ); |
| 5292 | 5308 | } |
| 5293 | 5309 | |
| 5294 | 5310 | return true; |