CVE-2026-108981 Overview
CVE-2026-108981 is a symlink attack vulnerability [CWE-61] in the ngx_cache_purge nginx module affecting versions before 3.0.4. The flaw allows file deletion when nginx and a served application, such as WordPress, run under the same user account. An attacker who can create a symbolic link inside the configured cache path can cause the purge operation to delete arbitrary files reachable by that user. The module follows symlinks while walking the cache directory tree because it relies on nginx's ngx_walk_tree() function, which uses stat() and dereferences links. Version 3.0.4 addresses the pre-planted symlink scenario but does not fully resolve a Time-of-Check Time-of-Use (TOCTOU) race condition.
Critical Impact
An authenticated local attacker with write access to the nginx cache directory can delete arbitrary files owned by the nginx service account, potentially corrupting application data or configuration.
Affected Products
- ngx_cache_purge nginx module versions before 3.0.4
- Deployments where nginx and web applications (e.g., WordPress) share a user account
- Systems where the attacker can write symlinks into the nginx cache path
Discovery Timeline
- 2026-10-12 - CVE-2026-108981 published to the National Vulnerability Database (NVD)
- 2026-10-16 - Last updated in NVD database
Technical Details for CVE-2026-108981
Vulnerability Analysis
The ngx_cache_purge module performs recursive directory traversal to remove cached content during purge operations. The module invokes nginx's internal ngx_walk_tree() helper, which uses stat() rather than lstat() when inspecting directory entries. Because stat() dereferences symbolic links, any symlink encountered during traversal is followed to its target, and the subsequent deletion operation acts on the resolved file instead of the link itself.
An attacker who can place a symlink inside the cache directory can redirect the purge logic to arbitrary files owned by the nginx user. In shared-user deployments where nginx and a web application run as the same account, this expands the deletion surface to application code, uploaded content, and configuration files. The attack requires local access and favorable file system conditions, limiting it to co-located adversaries.
Root Cause
The root cause is improper handling of symbolic links during cache tree traversal [CWE-61]. The reliance on stat() inside ngx_walk_tree() means the module cannot distinguish between regular files inside the cache and arbitrary targets referenced by attacker-controlled links.
Attack Vector
Exploitation requires local, low-privileged access to a user account that shares privileges with the nginx worker, typically through a vulnerable co-hosted application. The attacker creates a symlink inside the cache path pointing to a sensitive file, then triggers a cache purge. The attack complexity is high due to timing and placement requirements, especially after version 3.0.4 which closes the arbitrary-pre-placement window but leaves a TOCTOU race condition.
ngx_command_t *cmd, void *conf);
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);
static ngx_int_t ngx_http_purge_file_cache_delete_partial_file(
Source: GitHub ngx_cache_purge Commit a6da1352 — the patch introduces a pre_tree callback to validate directory entries before descending, mitigating symlink traversal during cache walks.
Detection Methods for CVE-2026-108981
Indicators of Compromise
- Unexpected symbolic links appearing inside nginx proxy_cache_path or fastcgi_cache_path directories
- Deletion of files outside the cache directory that are owned by the nginx service user
- Purge requests to ngx_cache_purge endpoints originating from co-located application processes
- Application errors following cache purge operations referencing missing configuration or content files
Detection Strategies
- Audit the cache directory for symbolic links using find /path/to/cache -type l on a scheduled basis
- Enable file integrity monitoring on application directories accessible to the nginx user
- Correlate nginx access logs for purge requests with file deletion events from the host audit subsystem
- Review nginx module version with nginx -V to identify builds containing ngx_cache_purge before 3.0.4
Monitoring Recommendations
- Deploy Linux auditd rules to track unlink() and unlinkat() syscalls executed by the nginx worker process
- Monitor for symlink() syscalls targeting the cache path from any process other than nginx
- Alert on cache purge requests outside expected administrative source addresses or scheduled jobs
How to Mitigate CVE-2026-108981
Immediate Actions Required
- Upgrade ngx_cache_purge to version 3.0.4 or later and rebuild nginx with the patched module
- Separate the nginx worker user from the application user so that shared deletion privileges no longer exist
- Restrict write access to the cache directory so that only the nginx worker can create entries
- Scan existing cache directories for pre-planted symlinks before applying the patch
Patch Information
The fix is available in ngx_cache_purge Release 3.0.4 and merged via Pull Request #72. The patch adds a ngx_http_purge_file_cache_pre_tree callback that validates each directory entry before traversal. Note that the maintainers acknowledge version 3.0.4 does not fully resolve the TOCTOU race condition, so defense in depth remains necessary.
Workarounds
- Run nginx under a dedicated system user that is not shared with any served application
- Mount the cache directory on a filesystem with the nosymfollow mount option where supported
- Disable the ngx_cache_purge module in environments where cache invalidation can be handled through alternate means
- Place the cache path on a filesystem where the application user has no write access
# Verify installed ngx_cache_purge version and inspect cache for symlinks
nginx -V 2>&1 | tr ' ' '\n' | grep cache_purge
find /var/cache/nginx -type l -printf '%p -> %l\n'
# Example: dedicated nginx user with restrictive cache ownership
chown -R nginx:nginx /var/cache/nginx
chmod 700 /var/cache/nginx
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

