⚠️ This issue respects the following points: ⚠️
Bug description
Monica CRM (v4.1.2, latest stable release) contains an unrestricted file upload vulnerability in the document upload endpoint ( POST /api/documents ). The application accepts files of any MIME type and extension with no validation, stores them in a publicly accessible directory served by Apache without authentication, and serves uploaded HTML files with Content-Type: text/html — causing browsers to execute embedded JavaScript in Monica's origin. An attacker with any valid Monica account (no admin rights required) can upload a malicious HTML file disguised as a business document, send the public URL to a logged-in victim, and silently exfiltrate all CRM contact data plus session tokens — enabling full account takeover. Introduced in PR #1912 and present in every release from v2.10.0 through v4.1.2.
Steps to reproduce
Two Monica accounts required — attacker ( user@test.local , any
privilege level) and victim ( admin@test.local , logged in with active
session).
-
Create malicious payload file — Create Q1-2025-Report.html
containing a JavaScript fetch to /api/contacts with
credentials:'include' . The file is disguised as a quarterly
business report.
-
Attacker uploads the file — Log in as attacker and upload Q1-
2025-Report.html via POST /api/documents . Monica returns HTTP
201 with "mime_type": "text/html" — no validation error.
-
Confirm unauthenticated access — Access the public URL
/storage/documents/.html without any cookies. Returns
HTTP 200 with Content-Type: text/html .
-
Attacker sends link to victim — URL is on Monica's own trusted
domain. Framed as: "Hey, check this Q1 2025 business report."
-
Victim clicks the link — XSS fires — JavaScript executes in
Monica's origin. Victim's session cookie is auto-sent with the fetch
call. All CRM contacts and XSRF-TOKEN are returned and
displayed.
Impact:
An attacker with any Monica account can silently steal all CRM contact
records, session tokens, and private notes from any logged-in user who
clicks a link. The captured XSRF-TOKEN and session cookies grant
persistent API access to the victim's entire account without knowing their
password. The attack requires one click, leaves no trace for the victim,
and the malicious URL is hosted on Monica's own trusted domain —
making it indistinguishable from a legitimate link. All personal relationship
data stored in Monica (contact names, phone numbers, addresses, notes,
journal entries) is at risk of exfiltration and the victim's account is fully
compromised.
Expected behavior
Recommended Remediation:
1 — Whitelist safe file types in
app/Services/Contact/Document/UploadDocument.php :
$request->validate([
'document' => ['required', 'file', 'mimes:pdf,doc,docx,jpg,jpeg,p
]);
2 — Require authentication to access uploaded files — serve files
through an authenticated controller route rather than directly from the
public filesystem.
3 — Force download for all uploaded files — set Content
Disposition: attachment and X-Content-Type-Options: nosniff
headers on the /storage/documents/ path to prevent browsers from
executing uploaded content.
Environment
app.monicahq.com (monica v4)
Version of Monica
4.1.2
Installation method
None
Web server
None
Database engine version
None
Additional info
No response
Bug description
Monica CRM (v4.1.2, latest stable release) contains an unrestricted file upload vulnerability in the document upload endpoint ( POST /api/documents ). The application accepts files of any MIME type and extension with no validation, stores them in a publicly accessible directory served by Apache without authentication, and serves uploaded HTML files with Content-Type: text/html — causing browsers to execute embedded JavaScript in Monica's origin. An attacker with any valid Monica account (no admin rights required) can upload a malicious HTML file disguised as a business document, send the public URL to a logged-in victim, and silently exfiltrate all CRM contact data plus session tokens — enabling full account takeover. Introduced in PR #1912 and present in every release from v2.10.0 through v4.1.2.
Steps to reproduce
Two Monica accounts required — attacker ( user@test.local , any
privilege level) and victim ( admin@test.local , logged in with active
session).
Create malicious payload file — Create Q1-2025-Report.html
containing a JavaScript fetch to /api/contacts with
credentials:'include' . The file is disguised as a quarterly
business report.
Attacker uploads the file — Log in as attacker and upload Q1-
2025-Report.html via POST /api/documents . Monica returns HTTP
201 with "mime_type": "text/html" — no validation error.
Confirm unauthenticated access — Access the public URL
/storage/documents/.html without any cookies. Returns
HTTP 200 with Content-Type: text/html .
Attacker sends link to victim — URL is on Monica's own trusted
domain. Framed as: "Hey, check this Q1 2025 business report."
Victim clicks the link — XSS fires — JavaScript executes in
Monica's origin. Victim's session cookie is auto-sent with the fetch
call. All CRM contacts and XSRF-TOKEN are returned and
displayed.
Impact:
An attacker with any Monica account can silently steal all CRM contact
records, session tokens, and private notes from any logged-in user who
clicks a link. The captured XSRF-TOKEN and session cookies grant
persistent API access to the victim's entire account without knowing their
password. The attack requires one click, leaves no trace for the victim,
and the malicious URL is hosted on Monica's own trusted domain —
making it indistinguishable from a legitimate link. All personal relationship
data stored in Monica (contact names, phone numbers, addresses, notes,
journal entries) is at risk of exfiltration and the victim's account is fully
compromised.
Expected behavior
Recommended Remediation:
1 — Whitelist safe file types in
app/Services/Contact/Document/UploadDocument.php :
$request->validate([
'document' => ['required', 'file', 'mimes:pdf,doc,docx,jpg,jpeg,p
]);
2 — Require authentication to access uploaded files — serve files
through an authenticated controller route rather than directly from the
public filesystem.
3 — Force download for all uploaded files — set Content
Disposition: attachment and X-Content-Type-Options: nosniff
headers on the /storage/documents/ path to prevent browsers from
executing uploaded content.
Environment
app.monicahq.com (monica v4)
Version of Monica
4.1.2
Installation method
None
Web server
None
Database engine version
None
Additional info
No response