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
Configuration values from the /api/config endpoint are placed directly into HTML value="" attributes without escaping in settings-advanced.js, enabling HTML attribute injection. A double quote in any config value breaks out of the attribute context. JavaScript execution is blocked by the server's CSP (script-src 'self'), but injected attributes can alter element styling for UI redressing. The primary attack vector is importing a malicious teleporter backup, which bypasses per-field server-side validation.
Details
In scripts/js/settings-advanced.js, config values are interpolated into HTML input elements without escapeHtml() at multiple locations:
// Line 92-95 (string type)
'<input type="text" class="form-control" value="' +
value.value + // <-- unescaped
'" data-key="' +
key + // <-- unescaped
// Line 131-134 (float type), 148-151 (integer type) — same pattern
A value.value containing " breaks out of the value="" attribute, allowing injection of arbitrary HTML attributes (style, placeholder, etc.). The same file uses utils.escapeHtml() for other fields (e.g., option.description at line 17, value.default at line 50), confirming the omission on value.value was an oversight.
CSP context: script-src 'self' blocks inline event handlers (onfocus, onmouseover, etc.), so attribute injection cannot achieve JavaScript execution. The practical impact is limited to CSS-based UI redressing via injected style attributes and altering form behavior via attributes like formaction (exploiting the missing form-action CSP directive).
Teleporter bypass: The PATCH /api/config endpoint validates individual fields — some reject double quotes (e.g., webserver.domain). However, the teleporter import (POST /api/teleporter) writes pihole.toml directly to disk without per-field validation. Fields like dns.interface, webserver.acl, and webserver.port also accept double quotes via the API without validation errors.
PoC
Prerequisites: Pi-hole Web v6.4.1; admin access to import a teleporter backup.
Method: Malicious teleporter backup
- Export a clean backup from Settings > Teleporter.
- Extract the ZIP and modify
etc/pihole/pihole.toml:
# Valid TOML — \" produces a literal " in the parsed value
interface = "\" style=\"background-color:red;border:3px solid red\" placeholder=\"INJECTED"
- Repackage:
zip -r malicious_backup.zip etc/
- Import via Settings > Teleporter > Restore (check only "Configuration").
- Navigate to Settings > All settings (
/admin/settings/all).
- Scroll to
dns.interface.
Result: The input field has a red background and shows "INJECTED" as placeholder text — the injected " closed the original value="" attribute and style/placeholder were added as new attributes. JavaScript event handlers (e.g., onfocus) are blocked by CSP.
Alternative direct API method (no teleporter needed):
curl -sk -X PATCH -H "X-FTL-SID: <SID>" -H "X-FTL-CSRF: <CSRF>" \
-H "Content-Type: application/json" "https://<pihole>/api/config" \
-d '{"config":{"dns":{"interface":"\" style=\"background:red\" placeholder=\"INJECTED"}}}'
This succeeds because dns.interface has no server-side validation for special characters.
Screenshot:

Impact
Stored HTML attribute injection. Authenticated Pi-hole administrators viewing the "All settings" page are affected after a malicious config value has been set. JavaScript execution is blocked by CSP (script-src 'self'), limiting impact to UI redressing via injected style attributes and potential form behavior manipulation via the missing form-action CSP directive. The primary vector is a crafted teleporter backup shared as a "recommended configuration" — the attacker needs no credentials, but an admin must import the file.
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
Configuration values from the
/api/configendpoint are placed directly into HTMLvalue=""attributes without escaping insettings-advanced.js, enabling HTML attribute injection. A double quote in any config value breaks out of the attribute context. JavaScript execution is blocked by the server's CSP (script-src 'self'), but injected attributes can alter element styling for UI redressing. The primary attack vector is importing a malicious teleporter backup, which bypasses per-field server-side validation.Details
In
scripts/js/settings-advanced.js, config values are interpolated into HTML input elements withoutescapeHtml()at multiple locations:A
value.valuecontaining"breaks out of thevalue=""attribute, allowing injection of arbitrary HTML attributes (style,placeholder, etc.). The same file usesutils.escapeHtml()for other fields (e.g.,option.descriptionat line 17,value.defaultat line 50), confirming the omission onvalue.valuewas an oversight.CSP context:
script-src 'self'blocks inline event handlers (onfocus,onmouseover, etc.), so attribute injection cannot achieve JavaScript execution. The practical impact is limited to CSS-based UI redressing via injectedstyleattributes and altering form behavior via attributes likeformaction(exploiting the missingform-actionCSP directive).Teleporter bypass: The
PATCH /api/configendpoint validates individual fields — some reject double quotes (e.g.,webserver.domain). However, the teleporter import (POST /api/teleporter) writespihole.tomldirectly to disk without per-field validation. Fields likedns.interface,webserver.acl, andwebserver.portalso accept double quotes via the API without validation errors.PoC
Prerequisites: Pi-hole Web v6.4.1; admin access to import a teleporter backup.
Method: Malicious teleporter backup
etc/pihole/pihole.toml:zip -r malicious_backup.zip etc//admin/settings/all).dns.interface.Result: The input field has a red background and shows "INJECTED" as placeholder text — the injected
"closed the originalvalue=""attribute andstyle/placeholderwere added as new attributes. JavaScript event handlers (e.g.,onfocus) are blocked by CSP.Alternative direct API method (no teleporter needed):
This succeeds because

dns.interfacehas no server-side validation for special characters.Screenshot:
Impact
Stored HTML attribute injection. Authenticated Pi-hole administrators viewing the "All settings" page are affected after a malicious config value has been set. JavaScript execution is blocked by CSP (
script-src 'self'), limiting impact to UI redressing via injected style attributes and potential form behavior manipulation via the missingform-actionCSP directive. The primary vector is a crafted teleporter backup shared as a "recommended configuration" — the attacker needs no credentials, but an admin must import the file.