CVE-2026-40519 Overview
CVE-2026-40519 is an authenticated remote code execution (RCE) vulnerability in Nginx Proxy Manager versions 2.9.14 through 2.15.1. The flaw resides in the setupCertbotPlugins() function in backend/setup.js, where user-supplied input from the dns_provider_credentials field is interpolated directly into a shell command. The command is executed via child_process.exec() without sanitization or escaping, triggering OS command injection [CWE-78] when the backend restarts. Authenticated users holding the certificates:manage permission can store a malicious payload that runs arbitrary commands on the host. The issue is fixed in commit a5db5ed.
Critical Impact
Authenticated attackers with certificate management rights can achieve arbitrary command execution on the Nginx Proxy Manager host, leading to full compromise of the reverse proxy infrastructure.
Affected Products
- Nginx Proxy Manager 2.9.14 through 2.15.1
- Deployments using the setupCertbotPlugins() flow with custom DNS provider credentials
- Container and bare-metal installations exposing the management API
Discovery Timeline
- 2026-06-08 - CVE-2026-40519 published to NVD
- 2026-06-09 - Last updated in NVD database
Technical Details for CVE-2026-40519
Vulnerability Analysis
The vulnerability is an OS command injection in the Node.js backend of Nginx Proxy Manager. When the application initializes Certbot DNS plugins, setupCertbotPlugins() builds a shell command string using the value of dns_provider_credentials supplied by an authenticated user. That string is passed to child_process.exec(), which spawns a shell to interpret the command. Because the user value is concatenated rather than passed as an argument array, shell metacharacters such as ;, &&, |, and $() are interpreted by /bin/sh. Any payload stored in the credentials field executes when the backend restarts and re-runs the setup logic. The vulnerability requires the certificates:manage permission, but exploitation grants code execution as the backend process user, typically root inside the container.
Root Cause
The root cause is unsafe string interpolation of user-controlled data into a shell command. The application relies on child_process.exec() instead of execFile() or spawn() with an argument array, and it does not validate or escape the dns_provider_credentials value before assembly. Restart-triggered execution makes the injection persistent and reliable.
Attack Vector
An authenticated attacker with the certificates:manage permission submits a crafted dns_provider_credentials value containing shell metacharacters and a payload. The payload is stored in the database. On the next backend restart, setupCertbotPlugins() invokes the shell command, which executes the injected payload alongside the legitimate Certbot setup.
// Security patch in backend/setup.js (commit a5db5ed)
// Merge pull request #5498 from Yasha-ops/develop
import settingModel from "./models/setting.js";
import userModel from "./models/user.js";
import userPermissionModel from "./models/user_permission.js";
+import fs from "fs/promises";
export const isSetup = async () => {
const row = await userModel.query().select("id").where("is_deleted", 0).first();
Source: GitHub Commit a5db5ed. The fix introduces fs/promises to write credentials to disk for Certbot instead of interpolating them into a shell command, eliminating the injection sink.
Detection Methods for CVE-2026-40519
Indicators of Compromise
- Unexpected child processes spawned by the Nginx Proxy Manager backend Node.js process, especially shells (/bin/sh -c) running non-Certbot commands.
- Anomalous outbound network connections originating from the proxy manager container shortly after a service restart.
- Database rows in the certificates table containing shell metacharacters (;, |, &&, $(), backticks) inside dns_provider_credentials.
- New files, cron jobs, or SSH keys appearing on the host filesystem after a backend restart.
Detection Strategies
- Inspect stored certificate records for dns_provider_credentials values containing shell control characters or command substitution syntax.
- Monitor process lineage for node or npm parents spawning sh, bash, curl, wget, or nc outside the normal Certbot workflow.
- Audit backend restart events and correlate them with subsequent process or network anomalies.
Monitoring Recommendations
- Enable command-line logging on hosts running Nginx Proxy Manager and alert on shells invoked by the backend service.
- Forward container and host telemetry to a centralized analytics platform for retrospective hunting across restart windows.
- Track authentication and authorization events for accounts holding the certificates:manage permission.
How to Mitigate CVE-2026-40519
Immediate Actions Required
- Upgrade Nginx Proxy Manager to a release that includes commit a5db5ed or later.
- Audit all existing certificate entries and remove any dns_provider_credentials values containing shell metacharacters.
- Review and reduce the number of accounts assigned the certificates:manage permission to least privilege.
- Rotate any secrets, API tokens, or credentials accessible from the proxy manager host, assuming potential compromise on vulnerable deployments.
Patch Information
The vulnerability is fixed in commit a5db5ed, merged via Pull Request #5498. The patch writes DNS provider credentials to a file using fs/promises instead of interpolating them into a shell command. Additional context is available in the VulnCheck Security Advisory.
Workarounds
- Restrict network access to the Nginx Proxy Manager admin interface to trusted management networks only.
- Disable or remove user accounts that do not require certificate management capabilities.
- Avoid restarting the backend until the patch is applied, since restart is the execution trigger for stored payloads.
# Verify installed version and update the container image
docker inspect nginx-proxy-manager --format '{{.Config.Image}}'
docker pull jc21/nginx-proxy-manager:latest
docker compose down && docker compose up -d
# Hunt for suspicious payloads in stored DNS provider credentials
sqlite3 /data/database.sqlite "SELECT id, nice_name, meta FROM certificate WHERE meta LIKE '%;%' OR meta LIKE '%\$(%' OR meta LIKE '%|%';"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

