From e198bd780a800f816ca936dc3080d6fb0202eea6 Mon Sep 17 00:00:00 2001 From: Jordan Diaz Date: Sat, 12 Sep 2026 22:59:07 +0000 Subject: [PATCH] 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 Claude-Session: https://claude.ai/code/session_01HPL66q9F33YZxbLPUT7KW8 --- cms/lib/handlers/handler_ws.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cms/lib/handlers/handler_ws.php b/cms/lib/handlers/handler_ws.php index 0cea669..458c55d 100755 --- a/cms/lib/handlers/handler_ws.php +++ b/cms/lib/handlers/handler_ws.php @@ -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;