A critical configuration-injection flaw in the froxlor hosting panel got a CVE record today, 97 days after the fix shipped. Both the vendor advisory and the CVE say the flaw was fixed in 2.2.5 — the code says the fix first appears in 2.3.8, twelve releases and 19 months later.
What happened
CVE-2026-90937 was published to the National Vulnerability Database today, September 14, 2026, at 1:19 p.m. UTC. It was assigned by VulnCheck, acting as a CNA, and carries a CVSS v3.1 base score of 9.9 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L) and a CVSS v4.0 score of 9.4, both from VulnCheck. The weakness is CWE-93, improper neutralization of CRLF sequences. As of this writing the NVD record’s vulnStatus is Received, meaning NVD has not yet done its own analysis.
The description reads, in full: “froxlor versions before 2.2.5 fail to validate newline characters in subdomain redirect URLs, allowing authenticated customers to inject arbitrary nginx or Apache configuration directives. Attackers can supply URLs containing literal newlines that are written verbatim into vhost config files during cron rebuild, enabling web server configuration corruption, denial of service, or hijacking of HTTP responses across hosted domains.”
Froxlor is an open-source server administration panel used to run shared hosting. Its whole job is to let a hosting customer manage their own domains, subdomains, mail and databases without touching the server. The privileges required here — PR:L in the vector — are the privileges of an ordinary hosting customer. The scope change (S:C) is the reason the score is 9.9: a directive injected into one tenant’s vhost block lands in a config file the whole web server reads.
The underlying vendor advisory is GHSA-c3p2-mj7v-5mrc, published to froxlor’s own repository on June 29, 2026 and credited to a reporter using the handle aslein1413-sys. It rates the issue Critical at 9.9 with the same vector. Its CVE ID field reads “No known CVE.” Its affected-versions field reads “< 2.2.5.” Its patched-versions field reads “2.3.8.”
Those last two fields cannot both be right. If everything below 2.2.5 is affected, then 2.2.5 is fixed; if the patch is in 2.3.8, then 2.2.5 through 2.3.7 are not. The advisory contradicts itself in two adjacent fields, and the CVE record published today inherited half of the contradiction: VulnCheck’s advisory lists the affected range as “>= 0 to < 2.2.5” and the fixed version as “2.2.5 and later.” The GHSA’s own mention of 2.3.8 did not travel with it.
The code settles it. Reading froxlor’s repository at the release tags:
lib/Froxlor/Validate/Validate.php is byte-for-byte identical at tags 2.2.4, 2.2.5 and 2.2.6 — MD5 fdbf1d9266c99ddcaa85a0985f69fc5f for all three. So is lib/Froxlor/Api/Commands/SubDomains.php at 2.2.4 and 2.2.5, at MD5 91fef3826dc7ba34b0e769a899d51beb. Nothing in either file changed when 2.2.5 shipped.
- The newline rejection — a loop over the URL’s path, query and fragment that returns false on
preg_match('/[\r\n]|%0a|%0d/i', ...), on decoded control characters, and on path traversal — first appears in validateUrl() at tag 2.3.8. It is absent at 2.3.7 and at every earlier tag checked. It is present at 2.3.9, 2.3.12 and 2.3.13.
Release dates, taken from the Packagist metadata for froxlor/froxlor: 2.2.5 shipped November 2, 2024. The fix shipped in 2.3.8 on June 9, 2026. Twelve releases sit in between and are marked not-affected by a record that does not describe them — 2.2.5, 2.2.6, 2.2.7, 2.2.8, and 2.3.0 through 2.3.7.
There is a trap in the middle of that range. Version 2.3.0, released December 3, 2025, rewrote both the calling function and validateUrl(): the regex-based URL check was replaced with a parse_url()-based one that validates scheme and host, and the caller now raises invaliddocumentrooturl instead of silently falling through to path handling. That is real hardening, and a reader skimming the diff could easily conclude the flaw was fixed there. It was not. Neither the 2.3.0 rewrite nor the 2.2.7 variant of it inspects the path component for carriage returns or line feeds. Only 2.3.8 does.
One more gap: https://github.com/advisories/GHSA-c3p2-mj7v-5mrc — the global GitHub Advisory Database entry — returned HTTP 404 when checked at 11:30 a.m. Central today, while other advisories published today resolve normally. The advisory appears to exist only as a repository-level advisory on froxlor’s own project, which is not the copy that dependency scanners consume.
Why it matters
An affected-version range is the one field in a vulnerability record that machines actually act on. Prose gets read by people who can notice a contradiction; versionEndExcluding: 2.2.5 gets read by a scanner that emits a green check and moves on. An operator running 2.3.5 today has a vulnerable panel, a scanner telling them they are clear, and a vendor advisory whose first line agrees with the scanner.
The 2.2 branch is where this bites hardest. Its newest release is 2.2.8, from July 8, 2025. There is no 2.2.9. Every 2.2.x release from 2.2.5 onward carries the unpatched validateUrl(), and the record tells all of them they are fine. An operator who stayed on 2.2 for compatibility reasons — the usual reason people stay on an old branch of a hosting panel — is told twice, by two different sources, that they have nothing to do. The correct advice for them is not “upgrade within your branch,” because there is nowhere to go; it is “leave the branch.”
This is the fourth time in a week this publication has found the affected range to be the least reliable field in a vulnerability record. AVideo’s seventeen CVEs carried a git commit hash where a version belonged, so scanners returned nothing at all. Snappy-java’s record pointed at a fixed version that did not exist in any release. ESPnet’s fix was real but depended on a PyTorch floor the metadata never stated. The failure mode differs each time; the consequence does not. A record can be accurate about the flaw and wrong about who has it, and only the second half is machine-readable.
The timing is its own artifact of how these systems fit together. The vendor published an advisory on June 29, 2026 that said “No known CVE.” A third-party CNA assigned one 77 days later, on September 14, 2026 — 97 days after the fix itself shipped. Neither system updates the other, so the advisory still says no CVE is known and the CVE still says 2.2.5 is safe. Both statements were reasonable when written and neither is true now.
What to do
Upgrade to 2.3.13, released August 28, 2026, which is the newest release and carries the fix. The minimum version that actually contains it is 2.3.8. Treat 2.2.5 as unfixed regardless of what your scanner says.
Do not take a scanner’s word for it on this one. The check is a two-second grep against the installed tree:
grep -c '%0a' lib/Froxlor/Validate/Validate.php
A result of zero means the newline rejection is not present and the panel is vulnerable, whatever version string it reports. The same file at a patched version returns a non-zero count.
If you are on 2.2.x, understand that upgrading means moving to the 2.3 branch. There is no patched 2.2 release to move to.
If you cannot upgrade immediately, the exposure is limited to customers who can create or modify subdomains with a redirect URL. Restricting that capability narrows it. Reviewing generated vhost files for directives nobody configured is the detection: the injected content is written verbatim into the config during the cron rebuild, so it is visible on disk. No exploitation of this flaw has been reported by the vendor, by VulnCheck, or by CISA.
Sourcing note
Checked: the NVD record for CVE-2026-90937 and the MITRE CVE Services record behind it; VulnCheck’s own advisory page; froxlor’s repository advisory GHSA-c3p2-mj7v-5mrc; the froxlor source at tags 2.2.3 through 2.3.13, read directly from raw.githubusercontent.com and compared by MD5 and by hand; and Packagist’s release metadata for froxlor/froxlor for release dates.
Not reached: GitHub’s API is gated from this environment, so commit history and commit dates could not be read; release dates come from Packagist rather than from GitHub. The global GitHub Advisory Database page for GHSA-c3p2-mj7v-5mrc returned 404 on a single check at 11:30 a.m. Central; that is one observation, not a confirmed absence, and it may resolve later.
Unresolved: whether froxlor considers the 2.2 branch end-of-life is not stated in any source read here, only that no 2.2 release exists after 2.2.8. Whether the vendor or VulnCheck will correct the affected range is unknown; neither has been asked. The CVE record is still at vulnStatus Received, so NVD’s own analysis, which may or may not reproduce the same range, has not happened yet. This story reports the dispute; it does not resolve it.