technova69/spip-check | 5 commits
Par Gilles Vincent, le 25 août 2026 à 13h41min :
Merge branch ‹ fix/deep-scan-accuracy › into ‹ main ›
fix: fiabiliser l’analyse approfondie
See merge request technova69/spip-check!4
Modifié
README.md
lang/spip_check_ar.php
lang/spip_check_ast.php
lang/spip_check_ca.php
lang/spip_check_cs.php
lang/spip_check_de.php
lang/spip_check_en.php
lang/spip_check_eo.php
lang/spip_check_es.php
lang/spip_check_eu.php
lang/spip_check_fa.php
lang/spip_check_fr.php
lang/spip_check_fr_tu.php
lang/spip_check_gl.php
lang/spip_check_hr.php
lang/spip_check_id.php
lang/spip_check_it.php
lang/spip_check_km.php
lang/spip_check_lb.php
lang/spip_check_nl.php
lang/spip_check_oc_lnc.php
lang/spip_check_oc_ni.php
lang/spip_check_pt.php
lang/spip_check_pt_br.php
lang/spip_check_ro.php
lang/spip_check_ru.php
lang/spip_check_sk.php
lang/spip_check_sv.php
lang/spip_check_tr.php
lang/spip_check_zh_tw.php
spip-check.php
src/SpipCheck.php
tests/unit/FileIndexerTest.php
tests/unit/IndexedScannerTest.php
tests/unit/ResultSelectionTest.php
tests/unit/ScannerTest.php
==============================
Par gilles, le 25 août 2026 à 13h33min :
fix: inspecter le contenu partout en mode approfondi
Le mode approfondi ne lisait le contenu que sous plugins/. Partout
ailleurs, inspectScript() sortait par return null dès qu’un fichier
était dans une liste blanche : index.php, mes_options.php,
config/connect.php, un formulaire CVT valide de
squelettes/formulaires/, tmp/meta_cache.php. Or c’est précisément
là qu’une porte dérobée s’ajoute le plus discrètement — à la fin d’un
fichier légitime — et le bouton « Scan approfondi » ne changeait donc
rien pour ces emplacements.
Les règles de structure sont extraites dans structuralFinding() et
gardent la priorité : un IMG/shell.php reste forbidden_writable_script
critique et déplaçable, il n’est pas rétrogradé en avertissement de
contenu. Quand la structure ne dit rien, le mode approfondi lit le
fichier via contentFinding(), quel que soit son emplacement, hors
bibliothèques embarquées. Le signalement reste plugin_webshell_marker
sous plugins/ et devient webshell_marker ailleurs.
classifyBatch() écartait par ailleurs les scripts autorisés de la
racine avant même la phase d’analyse : en mode approfondi ils sont
désormais des candidats, sans le raccourci unexpected_root_script qui
ne vaut que pour les noms inattendus.
Traductions des deux nouvelles règles dans les 29 catalogues complets.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Modifié
README.md
lang/spip_check_ar.php
lang/spip_check_ast.php
lang/spip_check_ca.php
lang/spip_check_cs.php
lang/spip_check_de.php
lang/spip_check_en.php
lang/spip_check_eo.php
lang/spip_check_es.php
lang/spip_check_eu.php
lang/spip_check_fa.php
lang/spip_check_fr.php
lang/spip_check_fr_tu.php
lang/spip_check_gl.php
lang/spip_check_hr.php
lang/spip_check_id.php
lang/spip_check_it.php
lang/spip_check_km.php
lang/spip_check_lb.php
lang/spip_check_nl.php
lang/spip_check_oc_lnc.php
lang/spip_check_oc_ni.php
lang/spip_check_pt.php
lang/spip_check_pt_br.php
lang/spip_check_ro.php
lang/spip_check_ru.php
lang/spip_check_sk.php
lang/spip_check_sv.php
lang/spip_check_tr.php
lang/spip_check_zh_tw.php
spip-check.php
src/SpipCheck.php
tests/unit/IndexedScannerTest.php
tests/unit/ScannerTest.php
==============================
Par gilles, le 25 août 2026 à 13h32min :
fix: plafonner la taille des fichiers inspectés
readRegularFile() chargeait le fichier entier en mémoire, .phar
compris. Un fichier volumineux provoquait une erreur fatale
memory_limit au milieu du lot ; after_id n’étant écrit qu’au retour
dans le template, la requête suivante repartait sur le même fichier :
l’analyse restait bloquée indéfiniment. La tokenisation introduite pour
les faux positifs a aggravé le coût mémoire, le tableau de tokens
pesant plusieurs fois la taille de la source.
La lecture s’arrête donc à 2 Mio, et le mode approfondi signale le
fichier au lieu de l’ignorer silencieusement : nouvelle règle
oversized_script, en revue manuelle. Le plafond couvre aussi les
lectures de paquet.xml et des formulaires CVT, où un fichier hors
gabarit fait simplement échouer la reconnaissance — donc signaler, pas
masquer. sha1RegularFile() n’est pas concerné : le hachage reste en
flux, à mémoire constante.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Modifié
lang/spip_check_ar.php
lang/spip_check_ast.php
lang/spip_check_ca.php
lang/spip_check_cs.php
lang/spip_check_de.php
lang/spip_check_en.php
lang/spip_check_eo.php
lang/spip_check_es.php
lang/spip_check_eu.php
lang/spip_check_fa.php
lang/spip_check_fr.php
lang/spip_check_fr_tu.php
lang/spip_check_gl.php
lang/spip_check_hr.php
lang/spip_check_id.php
lang/spip_check_it.php
lang/spip_check_km.php
lang/spip_check_lb.php
lang/spip_check_nl.php
lang/spip_check_oc_lnc.php
lang/spip_check_oc_ni.php
lang/spip_check_pt.php
lang/spip_check_pt_br.php
lang/spip_check_ro.php
lang/spip_check_ru.php
lang/spip_check_sk.php
lang/spip_check_sv.php
lang/spip_check_tr.php
lang/spip_check_zh_tw.php
spip-check.php
src/SpipCheck.php
tests/unit/ScannerTest.php
==============================
Par gilles, le 25 août 2026 à 13h16min :
fix: cibler l’exclusion des bibliothèques embarquées dans les plugins
Le mode approfondi signalait les bibliothèques tierces embarquées par
les plugins : PHPMailer (popen), symfony/process (proc_open), ou
un simple $pdo->exec($sql). Deux causes, deux correctifs.
D’abord le périmètre. Écarter tout répertoire nommé vendor depuis
FileIndexer aurait rendu le sous-arbre invisible pour toutes les
règles : un IMG/vendor/shell.php, local/vendor/backdoor.php ou
squelettes/vendor/porte.php n’aurait plus été signalé du tout, alors
que ces répertoires sont inscriptibles depuis le web et que le nom de
dossier à utiliser est public. L’indexeur parcourt donc l’arborescence
complète — seul le vendor/ de la racine, distribué par l’archive,
reste écarté — et l’exclusion passe au niveau de la règle :
inspectScript() ignore plugins/*/(…/)?(vendor|lib)/, que SPIP
n’auto-charge pas.
Ensuite la détection elle-même. hasPluginWebshellMarker()
travaillait sur le texte brut : une chaîne, un commentaire ou un appel
de méthode suffisaient à déclencher un signalement. Elle passe par
token_get_all(), comme isCvtForm(), et ne retient qu’un appel
direct — nom de fonction suivi de (, non précédé de ->, ?->,
::, function ou new. Les noms qualifiés PHP 8 (\exec()
restent détectés.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Modifié
spip-check.php
src/SpipCheck.php
tests/unit/FileIndexerTest.php
tests/unit/ScannerTest.php
Détails : https://git.spip.net/technova69/spip-check/-/commit/6588eda679f88c42b4ee4b4d5457e670ff91b1c5
==============================
Par gilles, le 25 août 2026 à 13h15min :
fix: fiabiliser le curseur d’analyse et la sélection déplaçable
Le curseur de scanBatch() avançait jusqu’au dernier candidat du lot
découpé, y compris lorsque le budget de temps interrompait la boucle
avant : les fichiers non scannés étaient silencieusement sautés et
done (alreadyScanned + scanned >= totalCandidates) n’était jamais
atteint, laissant l’étape analyser boucler indéfiniment. Le curseur
est désormais l’id du dernier candidat réellement scanné.
ResultSelection::group() calculait selectable sur la seule
existence du fichier et ignorait le champ fixable produit par les
règles. Un immutable_modified sur un fichier du cœur SPIP était donc
cochable, et « Tout sélectionner » + DEPLACER cassait le site. Une
ligne n’est cochable que si elle porte au moins un finding déplaçable ;
les autres écarts restent signalés pour revue manuelle. Le README
décrit la règle exacte.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Modifié
README.md
spip-check.php
src/SpipCheck.php
tests/unit/IndexedScannerTest.php
tests/unit/ResultSelectionTest.php
Détails : https://git.spip.net/technova69/spip-check/-/commit/e5081585e6cc9c1b5f89d487e0eee531c51b5df0