slug of the plugin that writes it. When that * plugin is installed, the file is "to identify" with the attribution * instead of "suspect" (control 4). * Source: test-fixtures/wp-env/PROBE.md §4 (clean install, WP Super Cache * writes wp-cache-config.php), decision of the orchestrator, 2026-10-23. */ const KNOWN_CONFIG_FILES = array( 'wp-cache-config.php' => 'wp-super-cache', ); /** * Markers that make wp-config.php an anomaly (plus include/require of a * file under the uploads folder, see Patterns::WP_CONFIG_INCLUDE). * Source: SPEC contrôle 1, 2026-10-23. */ const WP_CONFIG_MARKERS = array( '` (Patterns::IFMODULE_OPEN) * and this closing line. The lines inside are still judged one by one. * Source: DECISIONS 2026-10-24, Contact Form 7 6.2.3 wpcf7_uploads/.htaccess. */ const UPLOADS_ACCESS_CONTAINER_CLOSE = ''; /** * More lines an uploads .htaccess may hold (lowercased, whitespace collapsed): * the / containers (Patterns::FILES_OPEN and the closing lines * below) and the directives that remove PHP execution. The lines inside a * container are still judged one by one. The three Header lines are those of * WPForms (they only ask robots not to index and browsers to download). * Sources: DECISIONS 2026-10-24 (D-01); test-fixtures/real/sucuri-scanner-2.8.1/generated/ * and wpforms-lite-2.0.3/filesystem-media.php (both .htaccess contents), read 2026-10-23. */ const UPLOADS_ACCESS_FILES_CLOSE = array( '', '' ); const UPLOADS_ACCESS_NO_EXEC_LINES = array( 'sethandler none', 'sethandler default-handler', 'php_flag engine off', 'php_admin_flag engine off', 'options -execcgi' ); const UPLOADS_ACCESS_NO_EXEC_PREFIXES = array( 'removehandler ', 'removetype ' ); const UPLOADS_ACCESS_WPFORMS_HEADER_LINES = array( 'header set x-robots-tag "noindex"', 'header always set x-robots-tag "noindex"', 'header always set content-disposition "attachment"' ); /** * Files of the core checksums that differ between en_US and a localized * package; not compared when the locale fell back to en_US. * Source: N§A1 (fr_FR against en_US 7.1.3), SPEC Tranché 3, 2026-10-23. */ const LOCALE_DEPENDENT_FILES = array( 'wp-includes/version.php', 'readme.html', 'wp-config-sample.php' ); /** Core checksum entries under this prefix are ignored (N§A1, WP-CLI). */ const CORE_IGNORED_PREFIX = 'wp-content/'; /** The one wp-content/ entry of the core checksums still compared (N§A1 écart 2). */ const CORE_HELLO_KEY = 'wp-content/plugins/hello.php'; /** * Known auto_prepend_file targets of firewall plugins: file name => slug of the * plugin that writes it. Target absolute under ABSPATH without "..", plugin * installed → the directive is "to identify" with the attribution, and the same * file at the site root too; plugin absent → anomaly for the directive, suspect * for the root file (control 6 and control 1). * Sources: DECISIONS 2026-10-24 (D-02, D-03); test-fixtures/real/wordfence-9.0.2/generated/, * all-in-one-wp-security-and-firewall-5.4.10/wp-security-block-htaccess.php (get_contents()) * and generated/aios-bootstrap.php, ninjafirewall-4.9.2/install.php (NFW_HTACCESS_DATA: * NFW_LOG_DIR . '/nfwlog/ninjafirewall.php'), read 2026-10-23. */ const KNOWN_PREPEND_TARGETS = array( 'wordfence-waf.php' => 'wordfence', 'aios-bootstrap.php' => 'all-in-one-wp-security-and-firewall', 'ninjafirewall.php' => 'ninjafirewall', ); /** * Data files plugins write in the uploads folder: folder relative to the uploads * folder (any depth below) => slug. Plugin installed and inert opening block * (DATA_FILE_STOPS, UploadsRules::inertOpening()) → "to identify" with the attribution; * otherwise the rule of origin (anomaly). * Sources: DECISIONS 2026-10-24 (D-01, D-01 reste, D-02); test-fixtures/real/sucuri-scanner-2.8.1/base.lib.php * (dataStorePath(): WP_CONTENT_DIR . '/uploads/sucuri') and generated/sucuri-lastlogins.php; * sucuri-scanner 2.8.1 src/cache.lib.php (datastoreInfo(): ""), * read 2026-10-23 in the zip of REVIEW.md (SHA-256 identical); * test-fixtures/real/all-in-one-wp-security-and-firewall-5.4.10/generated/uploads-aios-firewall-rules-settings.php.head. */ const KNOWN_PLUGIN_DATA_FILES = array( 'sucuri' => 'sucuri-scanner', 'aios' => 'all-in-one-wp-security-and-firewall', ); /** * Statements that end a plugin data file before its data, compared exactly: the * opening PHP block holds only whitespace and comments before one of them (D-01 reste). */ const DATA_FILE_STOPS = array( 'exit(0);', '__halt_compiler();' ); /** * Options where an installed plugin keeps detection rules that hold the markers * it detects: option name => slug. Plugin installed → counted; absent → option_marker. * Source: DECISIONS 2026-10-24 (N-01); ninjafirewall 4.9.2 lib/class-firewall-config.php * (option_name = 'nfw_rules'), read 2026-10-23 in the zip of REVIEW.md (SHA-256 identical). */ const KNOWN_PLUGIN_OPTIONS = array( 'nfw_rules' => 'ninjafirewall', ); /** Directive names (SPEC contrôle 6, php.net ini.core, read 2026-10-23). */ const PREPEND_DIRECTIVES = array( 'auto_prepend_file', 'auto_append_file' ); /** Post statuses never read (SPEC contrôle 7). */ const CONTENT_EXCLUDED_STATUSES = array( 'auto-draft', 'trash', 'inherit' ); /** Above this size a file is not read (SPEC « Non regardé », contrôle 3). */ const CONTENT_MAX_BYTES = 5242880; /** Bytes read at the start of an uploads file to look for a PHP opening tag (SPEC contrôle 3). */ const HEAD_BYTES = 4096; /** Largest "silence" index.php in uploads (SPEC contrôle 3). */ const SILENCE_INDEX_MAX_BYTES = 200; /** Longest excerpt attached to a finding (SPEC contrôle 9). */ const EXCERPT_MAX_CHARS = 200; /** * Option and content markers: up to 3 excerpts around distinct occurrences, * joined by a newline, 600 characters in all (DECISIONS 2026-10-24, D-09). */ const EXCERPTS_MAX = 3; const EXCERPTS_TOTAL_MAX_CHARS = 600; /** * JSON-escaped forms of