Local privilege escalation through pihole-FTL ambient CAP_CHOWN capability
pihole-FTL runs as User=pihole but is granted ambient CAP_CHOWN by its systemd unit. CAP_CHOWN can be leveraged into root many ways (even self-contained in pihole scripts) one example is changing ownership of root-owned files to its own username, editing them, changing ownership back to root, waiting for their contents to be trusted by something privileged.
Any code execution in the pihole service context can get a root shell via the daily logrotate cron as an example. Which escalates the other code-exec-as-pihole bugs (disclosed separately) to root exec.
ProtectSystem=full is set in the systemd unit file, but is not as extensive as ProtectSystem=strict . This leaves a lot of files/paths open to taking advantage of using these capabilities.
The systemd unit grants CAP_CHOWN in AmbientCapabilities, so it is present in the effective set of FTL and inherited by children.
advanced/Templates/pihole-FTL.systemd:19-20
For one example of turning that into root code execution, Logrotate has a postrotate option that runs code after rotating the log (usually to signal service to write to new log file). Logrotate requires the file be root owned and not writeable by any other groups which we can satisfy.
/etc/pihole/logrotate is executed as root by the daily cron ( pihole flush once -> logrotate --force -> /etc/pihole/logrotate , advanced/Scripts/piholeLogFlush.sh ), and also @reboot .
For a self-contained pihole example, I did the following:
chown pihole:pihole /etc/pihole/logrotate
Edit /etc/pihole/logrotate to add a postrotate script
chown root:root /etc/pihole/logrotate
A plain pihole login shell (ssh or sudo -u pihole) does not have CAP_CHOWN. This requires running under the pihole-FTL process or one of its child processes.
Run in a context that has CAP_CHOWN (any FTL-child code exec like the separately reported issues). I am writing to /rootsh here as a demonstration of the ProtectSystem=full not being comprehensive. Could also write it to /etc/pihole/ though which is explicitly allowed.
Or one-line which seems to be the trend now:
Then you would wait for the logrotate cron job to run (midnight or a reboot). To run it once immediately to see the impact:
I confirmed this all live on an Ubuntu26 system with the latest pihole:
Local privilege escalation to root. Any code execution in the pihole-FTL service context (including separately-reported config -> exec bugs reachable via the config API, and unauthenticated when no admin password is set) is elevated from the unprivileged pihole user to full root.
Affected: Core v5.4 – v6.4.2 (current).
CAP_CHOWN was granted to the non-root pihole-FTL binary via setcap in v5.4 ( a1ee7d9 ) and moved into the systemd unit's AmbientCapabilities in v5.15 ( 8192733 ). It remains in the current unit.
Please let me know if you have any questions or I can do anything to help.
Should this lead to a CVE/advisory I would appreciate credit as Keith Linneman (LinnemanLabs).
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
