
Akaunting 3.1.21 - Authenticated stored XSS in document timeline
4.8
Medium
Detected by

Fluid Attacks AI SAST Scanner
Disclosed by
Oscar Naveda
Summary
Full name
Akaunting 3.1.21 - Authenticated stored XSS in document timeline through unescaped user names
Code name
State
Public
Release date
Affected product
Akaunting
Vendor
Akaunting
Affected version(s)
3.1.21
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: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
Yes
CVE ID(s)
Description
Akaunting 3.1.21 contains an authenticated stored cross-site scripting vulnerability in the document timeline shown on invoice and bill detail pages. An authenticated user can store HTML/JavaScript in their own profile name. When that user creates or cancels a document, Akaunting later uses the stored user name as the document owner name in translated timeline descriptions such as :user created this :type on :date. Those descriptions are rendered as raw Blade output in the accordion header component, so the attacker-controlled user name becomes executable HTML when another user views the affected document.
Vulnerability
Root cause
1. The profile update route accepts authenticated user-controlled names. The admin/profile route exposes user profile updates through Route::patch('profile/{user}', 'Auth\Users@update').
2. The user name validation only requires a string (app/Http/Requests/Auth/User.php:72-80). No HTML tag stripping or output-safe transformation is applied to name.
3. The update job stores the raw request input (app/Jobs/Auth/UpdateUser.php:27-29) within a database transaction.
4. Document timeline components read the stored owner name in app/View/Components/Documents/Show/Create.php and Restore.php by resolving the owner() relationship.
5. The user name is interpolated into translated HTML descriptions in resources/views/components/documents/show/create.blade.php and restore.blade.php using the trans() function.
6. The final accordion header renders the description as raw HTML in resources/views/components/show/accordion/head.blade.php using {!! $description !!}.
PoC
Store the payload in the user name: Update the profile name to CVE-RESTORE-"><img src=x onerror=alert(document.domain)>.
Create a document: Navigate to Sales -> Invoices -> New Invoice. Select a customer, add a line item, and save.
Trigger the XSS: Open the newly created invoice detail page as another authenticated user.
Confirm cancellation path: Cancel the invoice and reload the detail page to trigger the payload again from the cancellation timeline.
Evidence of exploitation
Video of exploitation
Static evidence

Our security policy
We have reserved the ID CVE-2026-11943 to refer to this issue from now on.
System Information
Akaunting
Version: 3.1.21
Operating System: Any
References
Github Repository: https://github.com/akaunting/akaunting
Mitigation
There is currently no patch available for this vulnerability.
Credits
The vulnerability was discovered by Oscar Naveda from Fluid Attacks' Offensive Team using the AI SAST Scanner.
Timeline
Vulnerability discovered
Vendor contacted
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.













