phpIPAM 1.4.4 - Stored XSS

4.8

Medium

Discovered by

Oscar Uribe

Offensive Team, Fluid Attacks

Summary

Full name

phpIPAM 1.4.4 - Stored XSS

Code name

State

Public

Release date

Affected product

phpIPAM

Affected version(s)

1.4.4

Fixed version(s)

1.4.5

Vulnerability name

Stored cross-site scripting (XSS)

Remotely exploitable

Yes

CVSS v4.0 vector string

CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N

CVSS v4.0 base score

4.8

Exploit available

No

Description

phpIPAM 1.4.4 stores the siteTitle setting from the server-settings form and later prints it as HTML in the application layout without output encoding. An attacker can therefore persist HTML and JavaScript that executes when another authenticated user loads a page containing the global header.

A regular authenticated account can request the settings route directly, obtain the CSRF token, and submit the form.

Vulnerability

Root Cause

app/admin/settings/settings-save.php accepts $_POST['siteTitle'] and puts it directly into the $values array passed to Admin::object_modify("settings", "edit", "id", $values). In the 1.4.4 code path there is no HTML sanitization or context-aware encoding before the value is stored.

The same endpoint checks only that the requester has a valid session and a CSRF token. It does not call User::is_admin(). The companion view, app/admin/settings/index.php, likewise creates a valid settings CSRF token after check_user_session() without an administrative authorization check. The menu being intended for administrators does not secure a directly requested route.

Source-to-sink path

  1. Source — authenticated user input: A logged-in user requests /?page=administration&section=settings. app/admin/settings/index.php:8-11 validates the session and creates a settings CSRF token; the page exposes a siteTitle form field at line 48.

  2. Write endpoint: The form is submitted to app/admin/settings/settings-save.php. Lines 18-21 validate a session and CSRF token but perform no is_admin() check.

  3. Persistent storage: app/admin/settings/settings-save.php:53-56 assigns $_POST['siteTitle'] to siteTitle, then calls Admin::object_modify to update the singleton settings record.

  4. Sink — raw HTML output: index.php:183 renders <?php print $User->settings->siteTitle; ?> inside the global header link. No htmlspecialchars, escaping helper, or sanitizer is applied at this output context. The same setting is also inserted in <title> and in the OpenSearch link title (index.php:88-91).

  5. Execution: A value such as <svg/onload=alert(document.domain)> becomes markup in the header and is interpreted by the browser whenever an authenticated victim visits an application page.

Impact

In phpIPAM 1.4.4, an authenticated administrator can persist a crafted Site title whose quote characters escape the value attribute of the Site title input. When another administrator opens the Server settings page, the browser parses the injected attributes and executes attacker-controlled JavaScript in that administrator's phpIPAM origin.

The script runs with the victim administrator's application privileges. It can read data available to that administrator, issue same-origin requests, and alter configuration or IPAM records through endpoints the victim may access. Exploitation requires both an administrator who can save the malicious title and an administrator who later loads the settings page; it is not an unauthenticated attack against ordinary visitors.

PoC

Preconditions

  • phpIPAM 1.4.4 is installed and reachable through a browser.

  • The attacker has a valid phpIPAM administrator account. Admin($Database) invokes is_admin() in both the administrative route and the save endpoint.

  • At least one authenticated victim, preferably an administrator to demonstrate impact, can subsequently load a normal phpIPAM page.

Step-by-step

  1. Sign in with an administrator account.

  2. Browse to http://<host>/?page=administration&section=settings.

  3. In Site title, enter the harmless demonstration payload below and keep the remaining required settings values unchanged:

    " autofocus onfocus=alert(1)>
    " autofocus onfocus=alert(1)>
    " autofocus onfocus=alert(1)>
    " autofocus onfocus=alert(1)>
  4. Save the settings. The request reaches app/admin/settings/settings-save.php, which persists the supplied siteTitle value.

  5. In a separate administrator browser session, open http://<host>/?page=administration&section=settings. The unescaped title breaks out of the input's value attribute, injects autofocus and onfocus, and executes the payload when the field receives focus.

  6. Confirm that the alert displays the phpIPAM origin. This establishes stored JavaScript execution; restore the original Site title immediately after testing.

Evidence of Exploitation

  • Static evidence:

Our security policy

We have reserved the ID CVE-2022-23045 to refer to this issue from now on.

Disclosure policy

System Information

  • Product: phpIPAM

  • Package name: phpipam/phpipam

  • Version: 1.4.4

  • Operating System: Any supported PHP web-server platform

  • PHP Version: 7.4

  • Database and version: Mysql

References

Mitigation

  1. Contain the exposure. Replace the current Site title with plain text, inspect settings.siteTitle for suspicious quote-based or HTML payloads, and restrict administrative-interface access to trusted administrators. If a malicious value may have been rendered to an administrator, invalidate or rotate active administrator sessions and review audit logs for unexpected changes.

  2. Remove the stored payload. Delete or replace malicious values already persisted in the settings table. Input filtering alone is insufficient because a value can arrive through upgrades, imports, direct database changes, or future write paths.

  3. Preserve output encoding and authorization. Encode siteTitle in every HTML text and attribute sink with an HTML-escaping routine such as htmlspecialchars($siteTitle, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'). Keep the administrator authorization checks on every settings view and state-changing endpoint. Add regression tests showing that a payload such as " autofocus onfocus=alert(1) x=" is rendered as text and cannot execute after persistence.

  4. Upgrade to the patched release. phpIPAM 1.4.5 contains the verified patch. In functions/classes/class.Common.php, Common_functions::get_settings() now applies escape_input() to siteTitle before caching it for rendering. escape_input() calls htmlentities($data, ENT_QUOTES), which encodes both quotes and HTML metacharacters and prevents the attribute-breaking payload used by this vulnerability. The v1.4.5 changelog also explicitly lists “Stored XSS in the "Site title" parameter” as a security fix. Upgrade to 1.4.5 or a later supported release and verify the installed version after deployment.

Credits

The vulnerability was discovered by Oscar Uribe from Fluid Attacks' Offensive Team.

Timeline

Vulnerability discovered

Vendor contacted

Vendor replied

Vulnerability patched

Public disclosure

Does your application use this vulnerable software?

During our free trial, our tools assess your application, identify vulnerabilities, and provide recommendations for their remediation.