fix(plugins): _removeFile solo borra contenido, nunca el motor

La regla anterior permitia cualquier ruta dentro de la raiz de la web, y eso
incluye cms/lib, lib o los PHP del motor. Ahora en modo fichero solo se admite
algo bajo cms/uploads/, template/, hooks/ o cache/; en modo plugin, una carpeta
directa de pluginsdir. Lo demas, 403.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HPL66q9F33YZxbLPUT7KW8
This commit is contained in:
Jordan Diaz
2026-09-12 22:59:07 +00:00
co-authored by Claude Fable 5.1
parent ea8eb6dbcb
commit e198bd780a
+8 -3
View File
@@ -450,9 +450,14 @@ function _removeFileRutaSegura($ruta, $esPlugin) {
$base = $pluginsDir;
$real = realpath($pluginsDir . '/' . $nombre);
} else {
if (strpos($ruta, "\0") !== false) return false;
$base = $raizWeb;
$real = realpath((substr($ruta, 0, 1) === '/') ? $ruta : $raizWeb . '/' . $ruta);
// Lista blanca: contenido de la web, nunca su motor ni su configuracion.
if (strpos($ruta, "\0") !== false || substr($ruta, 0, 1) === '/') return false;
$base = false;
foreach (array('cms/uploads', 'template', 'hooks', 'cache') as $permitido) {
if (strpos($ruta, $permitido . '/') === 0) { $base = realpath($raizWeb . '/' . $permitido); break; }
}
if (!$base) return false;
$real = realpath($raizWeb . '/' . $ruta);
}
if (!$real || $real === $base || $real === $pluginsDir || $real === $raizWeb) return false;
if (strpos($real, $base . DIRECTORY_SEPARATOR) !== 0) return false;