Package: release.debian.org Severity: normal Tags: trixie X-Debbugs-Cc: [email protected] Control: affects -1 + src:libnginx-mod-http-cache-purge User: [email protected] Usertags: pu
[ Reason ] This update backports the upstream fix for CVE-2026-108981 https://bugs.debian.org/1151200 Full and wildcard cache purges follow directory symlinks inside the cache tree. A symlink pointing outside the cache directory can therefore cause a purge to delete files outside that directory, subject to the nginx worker's filesystem permissions. [ Impact ] Without this update, affected installations remain exposed to unintended deletion of files outside the configured cache directory. [ Tests ] The upstream fix adds Test::Nginx regression tests for full purges and empty-prefix wildcard purges, checking that files outside the cache tree remain intact. Those tests were not included in this backport because the newer t/basic.t test suite is not present in version 2.5.3. [ Risks ] The change is small and limited to the two recursive purge walks present in version 2.5.3. It adds a pre-descent check using ngx_link_info() (lstat), skips directory symlinks and logs a warning. Directories whose metadata cannot be read are also skipped, with an error logged. [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [x] the issue is verified as fixed in unstable [ Changes ] * Add debian/patches/CVE-2026-108981.patch, backporting upstream commit a6da1352f52a8a02dd6828e88c39ed42fddcee96. diff -Nru libnginx-mod-http-cache-purge-2.5.3/debian/changelog libnginx-mod-http-cache-purge-2.5.3/debian/changelog --- libnginx-mod-http-cache-purge-2.5.3/debian/changelog 2025-04-11 12:26:56.000000000 +0000 +++ libnginx-mod-http-cache-purge-2.5.3/debian/changelog 2026-10-20 19:23:58.000000000 +0000 @@ -1,3 +1,11 @@ +libnginx-mod-http-cache-purge (1:2.5.3-3+deb13u1) trixie; urgency=high + + * d/p/CVE-2026-108981.patch: backport upstream fix to skip directory + symlinks during full and wildcard cache purges, preventing deletion of + files outside the cache directory (CVE-2026-108981). + + -- Jan Mojžíš <[email protected]> Tue, 20 Oct 2026 21:23:58 +0200 + libnginx-mod-http-cache-purge (1:2.5.3-3) unstable; urgency=medium * d/control: update my email to [email protected] diff -Nru libnginx-mod-http-cache-purge-2.5.3/debian/patches/CVE-2026-108981.patch libnginx-mod-http-cache-purge-2.5.3/debian/patches/CVE-2026-108981.patch --- libnginx-mod-http-cache-purge-2.5.3/debian/patches/CVE-2026-108981.patch 1970-01-01 00:00:00.000000000 +0000 +++ libnginx-mod-http-cache-purge-2.5.3/debian/patches/CVE-2026-108981.patch 2026-10-20 19:23:58.000000000 +0000 @@ -0,0 +1,120 @@ +From a6da1352f52a8a02dd6828e88c39ed42fddcee96 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hasan=20=C3=87ALI=C5=9EIR?= <[email protected]> +Date: Sat, 10 Oct 2026 18:22:46 +0300 +Subject: [PATCH] ngx_cache_purge: prevent symlink traversal during cache tree + walks (#72) +Origin: upstream, https://github.com/nginx-modules/ngx_cache_purge/commit/a6da1352f52a8a02dd6828e88c39ed42fddcee96 +Bug: https://github.com/nginx-modules/ngx_cache_purge/pull/72 +Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2026-108981 +Last-Update: 2026-10-20 + +Fix a security vulnerability where cache purge operations (purge_all, +wildcard, vary-aware exact, and background queue) follow symbolic links +planted inside the cache directory, allowing arbitrary file deletion +outside the cache path. + +Root cause: +All four purge walks rely on ngx_walk_tree(), which classifies directory +entries using stat() via ngx_de_info() and therefore follows symbolic links. +A "dir -> /elsewhere" link inside the cache path was treated as a real +directory and walked recursively. + +Fix: +Implement ngx_http_purge_file_cache_pre_tree() and use it as the +pre_tree_handler for all walks. Use ngx_link_info() (lstat) to inspect +directories before descent, skip symbolic links, and log a warning. + +Add Test::Nginx regression test cases (TEST 25 for purge_all and TEST 26 +for empty-prefix wildcard purge) to t/basic.t to ensure that purge +operations skip planted symbolic links and do not delete target files +outside the cache directory. + + +Debian trixie backport notes: + +Backported to 2.5.3: adjust the declaration and surrounding context, and +update the two existing tree walks (purge_all and wildcard/partial). +The vary-aware exact and background queue walks do not exist in 2.5.3. +Omit the t/basic.t changes because that newer test suite is not present +in 2.5.3. + +As in upstream, this prevents traversal of pre-existing directory symlinks; +the TOCTOU race between lstat() and opendir() remains unresolved. +--- + ngx_cache_purge_module.c | 39 +++++++++++++++++++++++++++++++++++++-- + 1 file changed, 37 insertions(+), 2 deletions(-) + +diff --git a/ngx_cache_purge_module.c b/ngx_cache_purge_module.c +index 251d3fed0dd05abcb8406d1db9fb91a70afa0c8a..685cac6eb72ba8211393ac0d3a2dc9aa9404dd0c 100644 +--- a/ngx_cache_purge_module.c ++++ b/ngx_cache_purge_module.c +@@ -122,6 +122,8 @@ char *ngx_http_cache_purge_response_type_conf(ngx_conf_t *cf, + static ngx_int_t + ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); + static ngx_int_t ++ngx_http_purge_file_cache_pre_tree(ngx_tree_ctx_t *ctx, ngx_str_t *path); ++static ngx_int_t + ngx_http_purge_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); + + ngx_int_t ngx_http_cache_purge_access_handler(ngx_http_request_t *r); +@@ -1301,6 +1303,39 @@ ngx_http_purge_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) { + return NGX_OK; + } + ++/* ++ * pre_tree_handler: never descend into a symbolic link found inside the ++ * cache tree. ++ * ++ * ngx_walk_tree() classifies every directory entry with stat(), which ++ * follows symbolic links, so a planted "dir -> /elsewhere" link would be ++ * walked (and its files purged) as if it were a real cache directory. ++ * nginx itself only ever creates regular directories and files in a cache ++ * path, therefore any symbolic link below the cache root is foreign and is ++ * skipped. The cache root itself is not passed to this handler, so a ++ * cache path that is a symbolic link keeps working. ++ */ ++static ngx_int_t ++ngx_http_purge_file_cache_pre_tree(ngx_tree_ctx_t *ctx, ngx_str_t *path) ++{ ++ ngx_file_info_t fi; ++ ++ if (ngx_link_info(path->data, &fi) == NGX_FILE_ERROR) { ++ ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ++ ngx_link_info_n " \"%V\" failed", path); ++ return NGX_DECLINED; ++ } ++ ++ if (ngx_is_link(&fi)) { ++ ngx_log_error(NGX_LOG_WARN, ctx->log, 0, ++ "ngx_cache_purge: skipping symbolic link in cache " ++ "tree \"%V\"", path); ++ return NGX_DECLINED; ++ } ++ ++ return NGX_OK; ++} ++ + static ngx_int_t + ngx_http_purge_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +@@ -1791,7 +1826,7 @@ ngx_http_cache_purge_all(ngx_http_request_t *r, ngx_http_file_cache_t *cache) { + ngx_tree_ctx_t tree; + tree.init_handler = NULL; + tree.file_handler = ngx_http_purge_file_cache_delete_file; +- tree.pre_tree_handler = ngx_http_purge_file_cache_noop; ++ tree.pre_tree_handler = ngx_http_purge_file_cache_pre_tree; + tree.post_tree_handler = ngx_http_purge_file_cache_noop; + tree.spec_handler = ngx_http_purge_file_cache_noop; + tree.data = NULL; +@@ -1824,7 +1859,7 @@ ngx_http_cache_purge_partial(ngx_http_request_t *r, ngx_http_file_cache_t *cache + ngx_tree_ctx_t tree; + tree.init_handler = NULL; + tree.file_handler = ngx_http_purge_file_cache_delete_partial_file; +- tree.pre_tree_handler = ngx_http_purge_file_cache_noop; ++ tree.pre_tree_handler = ngx_http_purge_file_cache_pre_tree; + tree.post_tree_handler = ngx_http_purge_file_cache_noop; + tree.spec_handler = ngx_http_purge_file_cache_noop; + tree.data = key_partial; +-- +2.47.3 + diff -Nru libnginx-mod-http-cache-purge-2.5.3/debian/patches/series libnginx-mod-http-cache-purge-2.5.3/debian/patches/series --- libnginx-mod-http-cache-purge-2.5.3/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ libnginx-mod-http-cache-purge-2.5.3/debian/patches/series 2026-10-20 19:23:58.000000000 +0000 @@ -0,0 +1 @@ +CVE-2026-108981.patch

