NginxProxyManager / NginxProxyManager/nginx-proxy-manager

RCE via Shell Injection in DNS Credentials (Nginx Proxy Manager) - CVE-2026-40519

Open Beginner friendly
#5,478 6 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
34.2k
Forks
3.9k
Avg merge
21h 12m
Merged PRs (30d)
20

Description

Summary

Nginx Proxy Manager is vulnerable to authenticated remote code execution due to a shell injection in setupCertbotPlugins() (backend/setup.js).

The user-controlled field dns_provider_credentials is interpolated into a shell command executed via child_process.exec() without proper escaping.
An attacker with certificates:manage permission can inject arbitrary commands, executed on backend restart (typically as root in Docker deployments).

Affected Versions

v2.9.14   v2.9.15   v2.9.16   v2.9.17   v2.9.18   v2.9.19   v2.9.20
v2.9.21   v2.9.22
v2.10.0   v2.10.1   v2.10.2   v2.10.3   v2.10.4
v2.11.0   v2.11.1   v2.11.2   v2.11.3
v2.12.0   v2.12.1   v2.12.2   v2.12.3   v2.12.4   v2.12.5   v2.12.6
v2.13.0   v2.13.1   v2.13.2   v2.13.3   v2.13.4   v2.13.5   v2.13.6   v2.13.7
v2.14.0   (latest, still vulnerable)

Root Cause

Incorrect escaping order:

const escapedCredentials = certificate.meta.dns_provider_credentials
    .replaceAll("'", "\\'")
    .replaceAll("\\", "\\\\");

Backslashes are escaped after single quotes, breaking the protection and allowing injection.
Example input:

x' ; cmd ; #

Results in command execution:

echo 'x\\' ; cmd ; #'

Exploitation

  1. Store payload in dns_provider_credentials (DB or race condition)
  2. Restart backend
  3. Payload executes via /bin/sh -c inside exec()

Reliable in Docker since /etc/letsencrypt/credentials/ is not persisted.
Example payload:

fake' > /dev/null; CMD ; echo '

Impact

  • Full RCE
  • Access to secrets, TLS keys, database
  • Service disruption and persistence

Fix

.replaceAll("\\", "\\\\")
.replaceAll("'", "\\'");

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in backend/setup.js at setupCertbotPlugins() and trace how dns_provider_credentials reaches child_process.exec(). Verify the escaping behavior with the payload pattern described in the issue, then add regression coverage showing that credentials cannot alter the shell command while normal DNS credentials still work.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, javascript
Domain
backend, security
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.