Skip to content

Stored HTML attribute injection

Moderate
PromoFaux published GHSA-9rfm-c5g6-538p Apr 3, 2026

Package

No package listed

Affected versions

v6.0 - v6.4.1

Patched versions

6.5

Description

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

  1. Export a clean backup from Settings > Teleporter.
  2. 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"
  1. Repackage: zip -r malicious_backup.zip etc/
  2. Import via Settings > Teleporter > Restore (check only "Configuration").
  3. Navigate to Settings > All settings (/admin/settings/all).
  4. 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:
image

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.

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N

CVE ID

CVE-2026-33406

Weaknesses

No CWEs

Credits