From 1f5a9d3fb1a3ba1664c4326c085a5059fcbaf620 Mon Sep 17 00:00:00 2001 From: KuJoe <1040086+KuJoe@users.noreply.github.com> Date: Sat, 21 Mar 2026 13:26:20 -0400 Subject: [PATCH] Update the delete_post, delete_page, and delete_comment functions All delete functions now check to ensure the file has a .md extension and is in the /content/ directory. --- system/admin/admin.php | 72 +++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/system/admin/admin.php b/system/admin/admin.php index 1e4a09f5..f89c9c7b 100644 --- a/system/admin/admin.php +++ b/system/admin/admin.php @@ -1129,39 +1129,52 @@ function delete_post($file, $destination) { if (!login()) return null; - $deleted_content = $file; $user = $_SESSION[site_url()]['user']; $role = user('role', $user); - $arr = explode('/', $file); - - // realpath resolves all traversal operations like ../ + + // Resolve user-supplied path and content root to canonical paths. $realFilePath = realpath($file); + $realContentDir = realpath('content'); + if ($realFilePath === false || $realContentDir === false) { + return; + } - // realpath returns an empty string if the file does not exist - if ($realFilePath == '') { + // Ensure file is inside content/ (with directory boundary protection). + $contentDir = rtrim($realContentDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; + if (strpos($realFilePath, $contentDir) !== 0) { return; } - // get the current project working directory - $cwd = getcwd(); + if (strtolower(pathinfo($realFilePath, PATHINFO_EXTENSION)) !== 'md') { + return; + } - // content directory relative to the current project working directory - $contentDir = $cwd . DIRECTORY_SEPARATOR . 'content'; + $deleted_content = $realFilePath; + $relativePath = str_replace('\\', '/', substr($realFilePath, strlen($contentDir))); + $pathParts = explode('/', $relativePath); + $postOwner = isset($pathParts[0]) ? $pathParts[0] : null; - // if the file path does not start with $contentDir, it means its accessing - // files in folders other than content - if (strpos($realFilePath, $contentDir) !== 0) { + if (count($pathParts) < 5 || $pathParts[1] !== 'blog') { return; } // Get cache file - $info = pathinfo($file); + $info = pathinfo($relativePath); $fn = explode('_', $info['basename']); - $dr = explode('/', $info['dirname']); - clear_post_cache($fn[0], $fn[1], str_replace('.md', '', $fn[2]), $file, $dr[3], $dr[4]); + if (count($fn) < 3) { + return; + } + + $category = isset($pathParts[2]) ? $pathParts[2] : null; + $type = isset($pathParts[3]) ? $pathParts[3] : null; + if ($category === null || $type === null) { + return; + } + + clear_post_cache($fn[0], $fn[1], str_replace('.md', '', $fn[2]), $deleted_content, $category, $type); if (!empty($deleted_content)) { - if ($user === $arr[1] || $role === 'editor' || $role === 'admin') { + if ($user === $postOwner || $role === 'editor' || $role === 'admin') { unlink($deleted_content); delete_comments($deleted_content); rebuilt_cache('all'); @@ -1181,7 +1194,6 @@ function delete_page($file, $destination) { if (!login()) return null; - $deleted_content = $file; $user = $_SESSION[site_url()]['user']; $role = user('role', $user); @@ -1205,6 +1217,12 @@ function delete_page($file, $destination) return; } + if (strtolower(pathinfo($realFilePath, PATHINFO_EXTENSION)) !== 'md') { + return; + } + + $deleted_content = $realFilePath; + if (!empty($menu)) { foreach (glob('cache/page/*.cache', GLOB_NOSORT) as $file) { unlink($file); @@ -2012,7 +2030,23 @@ function rename_comments($oldfile, $newfile) { function delete_comments($mdfile) { - $file_comments = get_comments_file_from_md($mdfile); + if (strtolower(pathinfo($mdfile, PATHINFO_EXTENSION)) !== 'md') { + return false; + } + + $realContentDir = realpath('content'); + $realTargetDir = realpath(dirname($mdfile)); + if ($realContentDir === false || $realTargetDir === false) { + return false; + } + + $targetFile = $realTargetDir . DIRECTORY_SEPARATOR . basename($mdfile); + $contentDir = rtrim($realContentDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; + if (strpos($targetFile, $contentDir) !== 0) { + return false; + } + + $file_comments = get_comments_file_from_md($targetFile); if (is_file($file_comments)) { unlink($file_comments); return true;