Please do not report security vulnerabilities through public GitHub issues.
If you discover a security vulnerability in PatchPanel, please report it through a private channel:
- Go to the GitHub Security Advisory page
- Click "Report a vulnerability"
- Fill out the advisory form with detailed information
- Submit the advisory
- Description of the vulnerability
- Steps to reproduce the issue
- Potential impact of the vulnerability
- Affected versions (if known)
- Suggested fix (if you have one)
- Your contact information for follow-up questions
Maintained as a side-project with limited resources. Realistic timeline:
- Initial response: 48–72 hours
- Assessment: within 1 week
- Resolution: typically 1–4 weeks depending on severity
- Disclosure: coordinated, after a fix is available
- Critical: RCE, privilege escalation. Immediate attention.
- High: authentication bypass, key disclosure, data exfiltration. Days.
- Medium: DoS, information disclosure. Standard timeline.
- Low: minor information leaks. Lower priority.
PatchPanel renders configuration for HAProxy — a TLS-terminating reverse proxy that frequently sits on a public IP — and reloads it via HAProxy's master control socket. The blast radius of a PatchPanel vulnerability is the same as HAProxy's blast radius. Special attention to:
- HAProxy config injection — any path that lets unprivileged input land
in the rendered
haproxy.cfgwithout escaping (ACL values, header names, regex bodies, hostnames, server addresses) - Master CLI socket access — unauthorized reloads, server-state
changes, or stick-table mutations via
/run/haproxy-master.sock - Certificate / key handling — path traversal in BYO cert / trusted CA / CRL uploads; private key disclosure via the cfg-render endpoint or audit log
- API key authentication — bcrypt-bypass, expired-key acceptance, permission-scope confusion
- ACME challenge endpoints — path traversal in
/.well-known/, spoofed validation responses - Command execution — PatchPanel shells out to
certbot,haproxy -c,openssl, and the OS toolchain. Argument-injection surface lives there - State document validation — Zod-schema bypass that lets a malformed
state through validation but crashes
haproxy -c
PatchPanel runs in two modes. The threat model differs.
The PatchPanel HTTP server speaks plain HTTP on a Docker-internal port and is reached only through the supervisor's ingress proxy. TLS, public exposure, authentication, and access control are HA's responsibility. The add-on:
- Trusts the supervisor proxy IP via
app.set('trust proxy', ...) - Reads
X-Ingress-Pathfor asset URL prefixing - Reads
X-Remote-User-*for audit-log attribution - Runs no local authentication, no session cookies, no CSRF middleware, no first-run wizard
Misconfiguring trust proxy or exposing the add-on's internal port outside
the supervisor breaks the security model.
PatchPanel terminates its own TLS and runs its own auth. The intended hardening (some implemented today, some on the roadmap):
| Area | Implementation | Status |
|---|---|---|
| TLS bootstrap | Self-signed cert generated via openssl req -x509 -nodes -days 365 -newkey rsa:2048 |
Planned |
| TLS hardening | minVersion: TLSv1.2, maxVersion: TLSv1.3, ECDHE-only ciphers, honorCipherOrder |
Planned |
| HSTS / CSP / frame | helmet with CSP, HSTS (max-age + includeSubDomains + preload), X-Frame-Options DENY |
Planned |
| Session auth | express-session + better-sqlite3 store, httpOnly + Secure + SameSite=Lax cookie |
Planned |
| API key auth | bcrypt cost 12, per-key permission scopes, optional ≤1-year expiry, 8-char preview |
Planned |
| Retrievable keys | Optional AES-256-CBC encrypted full-key column (off by default) | Planned |
| Password hashing | bcrypt cost 12 for the local admin |
Planned |
| CSRF | lusca.csrf() gated to cookie-authenticated routes (skipped for Bearer + GET + SSE) |
Planned |
| CORS | cors package with whitelist origin array, credentials: true |
Planned |
| Rate limiting | express-rate-limit tiered: auth-strict, write, read-permissive |
Planned |
| Input validation | zod schemas at every API entry point + state-document schema |
Partial |
| First-run gate | Setup-only mode until /etc/patchpanel/setup.token is consumed; timing-safe compare |
Planned |
| Audit log | Every state mutation persisted to audit.sqlite with actor + outcome |
Implemented |
| HAProxy validation | haproxy -c against rendered cfg before atomic swap |
Implemented |
| Path traversal | All cert / CA / CRL paths resolved + bounded to dedicated directories | Implemented |
"Partial" for input validation = the HAProxy state document is fully Zod-validated today; the rest of the API surface validates ad-hoc.
The "Planned" rows correspond to roadmap items tracked in
GitHub Issues under
the security label. Until they land, run standalone PatchPanel behind
a trusted network or another reverse proxy that does TLS / auth for you.
- Keep PatchPanel updated. Subscribe to releases.
- Run on the latest LTS Node.js — current target is Node 22+.
- Use a real (Let's Encrypt) cert for the management UI itself, not the self-signed bootstrap.
- Restrict network access to the management port. Even with auth, the smaller the exposure the better.
- Rotate API keys at least annually; set the shortest practical expiry.
- Grant the narrowest permissions an integration needs. A read-only key
is harmless if leaked; a
haproxy-controlkey is not. - Watch the audit log for unexpected key usage.
Contributors who responsibly report security vulnerabilities will be acknowledged here (with their permission):
- No vulnerabilities reported yet.
This security policy may be updated as the project evolves. Check back periodically.