Skip to main content
Vulnerability Database/CVE-2026-108981

CVE-2026-108981: ngx_cache_purge Race Condition Vulnerability

CVE-2026-108981 is a race condition flaw in ngx_cache_purge that enables file deletion through symlink attacks when nginx shares user accounts with applications. This article covers technical details, affected versions, impact assessment, and mitigation strategies.

Published:

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.

c
     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
bash
# 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.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.