CVE-2026-41237
Froxlor has an incomplete fix for CVE-2026-30932
Froxlor is open source server administration software. In version 2.3.6 and earlier, the LOC record regex uses \s+ which matches newlines (allowing embedded newlines to pass), TLSA matchingType=0 has no upper bound on hex data length, and all validators return raw input without zone-file escaping. Version 2.3.7 contains an updated patch.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
8.6
Froxlor has an incomplete fix for CVE-2026-30932
Froxlor is open source server administration software. In version 2.3.6 and earlier, the LOC record regex uses \s+ which matches newlines (allowing embedded newlines to pass), TLSA matchingType=0 has no upper bound on hex data length, and all validators return raw input without zone-file escaping. Version 2.3.7 contains an updated patch.
- Record
CVE-2026-41237- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-74
- Updated
- 2026-11-02
EUVDEUVD-2026-34316
8.6
Froxlor is open source server administration software. In version 2.3.6 and earlier, the LOC record regex uses \s+ which matches newlines (allowing embedded newlines to pass), TLSA matchingType=0 has no upper bound on hex data length, and all validators return raw input without zone-file escaping. Version 2.3.7 contains an updated patch.
- Record
EUVD-2026-34316- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-j6fm-9rfm-j5hx
8.6
Froxlor has an incomplete fix for CVE-2026-30932
Summary
The LOC record regex uses \s+ which matches newlines (allowing embedded newlines to pass), TLSA matchingType=0 has no upper bound on hex data length, and all validators return raw input without zone-file escaping.
Affected Package
- Ecosystem: Other
- Package: froxlor
- Affected versions: all versions before fix commit b34829262dc3
- Patched versions: >= commit b34829262dc3
Severity
Medium -- CVSS
CWE
CWE-74 -- Improper Neutralization of Special Elements in Output Used by a Downstream Component (Injection)
Details
DNS record content is concatenated directly into bind9 zone files at DnsEntry.php line 83. Before the fix, LOC/RP/SSHFP/TLSA records had no content validation at all, enabling zone file injection via embedded newlines.
The fix adds format-specific regexes and field validation but has gaps: the LOC regex's \s+ matches newlines in PHP's PCRE engine, allowing a LOC record with a newline between fields to pass validation but produce multiple lines in the zone file. TLSA matchingType=0 only requires len(data) >= 2 with no upper bound, enabling arbitrarily large payloads. All validators return raw input without zone-file escaping.
PoC
#!/usr/bin/env python3
"""
CVE-2026-30932 - Incomplete DNS Record Content Validation in froxlor/froxlor
Affected component: lib/Froxlor/Api/Commands/DomainZones.php
Vulnerability type: Input Validation / DNS Zone File Injection
Patch: https://github.com/froxlor/froxlor/commit/b34829262dc32818b37f6a1eabb426d0b277a86b
The patch adds validation for LOC, RP, SSHFP, and TLSA DNS record types.
However, the sanitization is incomplete:
1. PRE-FIX: No validation at all - arbitrary content stored as DNS records.
2. POST-FIX BYPASS: LOC regex \s+ matches newlines; TLSA matchingType=0
allows unbounded hex data; validators return raw input without escaping.
"""
import re
import sys
import string
def vulnerable_add_record(record_type, content):
"""Pre-fix: no validation for LOC, RP, SSHFP, TLSA."""
errors = []
if record_type in ('LOC', 'RP', 'SSHFP', 'TLSA') and content:
pass
return {"errors": errors, "content": content}
def validate_dns_loc(inp):
"""Replicates Validate::validateDnsLoc from the patch."""
pattern = re.compile(
r'^'
r'(\d{1,2})\s+'
r'(\d{1,2})\s+'
r'(\d{1,2}(?:\.\d+)?)\s+'
r'([NS])\s+'
r'(\d{1,3})\s+'
r'(\d{1,2})\s+'
r'(\d{1,2}(?:\.\d+)?)\s+'
r'([EW])\s+'
r'(-?\d+(?:\.\d+)?)m'
r'(?:\s+(\d+(?:\.\d+)?)m'
r'(?:\s+(\d+(?:\.\d+)?)m'
r'(?:\s+(\d+(?:\.\d+)?)m)?'
r')?)?$',
re.DOTALL
)
m = pattern.match(inp)
if not m:
return False
lat_deg = int(m.group(1))
lat_min = int(m.group(2))
lat_sec = float(m.group(3))
lon_deg = int(m.group(5))
lon_min = int(m.group(6))
lon_sec = float(m.group(7))
if lat_deg > 90: return False
if lat_min > 59: return False
if lat_sec >= 60: return False
if lon_deg > 180: return False
if lon_min > 59: return False
if lon_sec >= 60: return False
return inp
def validate_dns_sshfp(inp):
"""Replicates Validate::validateDnsSshfp from the patch."""
parts = inp.strip().split()
if len(parts) != 3:
return False
algorithm, fp_type, fingerprint = parts
valid_algorithms = [1, 2, 3, 4, 6]
if not algorithm.isdigit() or int(algorithm) not in valid_algorithms:
return False
valid_types = [1, 2]
if not fp_type.isdigit() or int(fp_type) not in valid_types:
return False
if not all(c in string.hexdigits for c in fingerprint):
return False
fp_type_int = int(fp_type)
expected = {1: 40, 2: 64}.get(fp_type_int, 0)
if len(fingerprint) != expected:
return False
return inp
def validate_dns_tlsa(inp):
"""Replicates Validate::validateDnsTlsa from the patch."""
parts =…
- Record
GHSA-j6fm-9rfm-j5hx- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-74
- Updated
- 2026-11-02
NVD
8.6
Froxlor is open source server administration software. In version 2.3.6 and earlier, the LOC record regex uses \s+ which matches newlines (allowing embedded newlines to pass), TLSA matchingType=0 has no upper bound on hex data length, and all validators return raw input without zone-file escaping. Version 2.3.7 contains an updated patch.
- Record
CVE-2026-41237- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - Weakness
- CWE-74
- Updated
- 2026-11-02
OSV
8.6
Froxlor has an incomplete fix for CVE-2026-30932
Froxlor is open source server administration software. In version 2.3.6 and earlier, the LOC record regex uses \s+ which matches newlines (allowing embedded newlines to pass), TLSA matchingType=0 has no upper bound on hex data length, and all validators return raw input without zone-file escaping. Version 2.3.7 contains an updated patch.
- Record
CVE-2026-41237- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-74
- Updated
- 2026-11-02
OSVGHSA-j6fm-9rfm-j5hx
8.6
Froxlor has an incomplete fix for CVE-2026-30932
Summary
The LOC record regex uses \s+ which matches newlines (allowing embedded newlines to pass), TLSA matchingType=0 has no upper bound on hex data length, and all validators return raw input without zone-file escaping.
Affected Package
- Ecosystem: Other
- Package: froxlor
- Affected versions: all versions before fix commit b34829262dc3
- Patched versions: >= commit b34829262dc3
Severity
Medium -- CVSS
CWE
CWE-74 -- Improper Neutralization of Special Elements in Output Used by a Downstream Component (Injection)
Details
DNS record content is concatenated directly into bind9 zone files at DnsEntry.php line 83. Before the fix, LOC/RP/SSHFP/TLSA records had no content validation at all, enabling zone file injection via embedded newlines.
The fix adds format-specific regexes and field validation but has gaps: the LOC regex's \s+ matches newlines in PHP's PCRE engine, allowing a LOC record with a newline between fields to pass validation but produce multiple lines in the zone file. TLSA matchingType=0 only requires len(data) >= 2 with no upper bound, enabling arbitrarily large payloads. All validators return raw input without zone-file escaping.
PoC
#!/usr/bin/env python3
"""
CVE-2026-30932 - Incomplete DNS Record Content Validation in froxlor/froxlor
Affected component: lib/Froxlor/Api/Commands/DomainZones.php
Vulnerability type: Input Validation / DNS Zone File Injection
Patch: https://github.com/froxlor/froxlor/commit/b34829262dc32818b37f6a1eabb426d0b277a86b
The patch adds validation for LOC, RP, SSHFP, and TLSA DNS record types.
However, the sanitization is incomplete:
1. PRE-FIX: No validation at all - arbitrary content stored as DNS records.
2. POST-FIX BYPASS: LOC regex \s+ matches newlines; TLSA matchingType=0
allows unbounded hex data; validators return raw input without escaping.
"""
import re
import sys
import string
def vulnerable_add_record(record_type, content):
"""Pre-fix: no validation for LOC, RP, SSHFP, TLSA."""
errors = []
if record_type in ('LOC', 'RP', 'SSHFP', 'TLSA') and content:
pass
return {"errors": errors, "content": content}
def validate_dns_loc(inp):
"""Replicates Validate::validateDnsLoc from the patch."""
pattern = re.compile(
r'^'
r'(\d{1,2})\s+'
r'(\d{1,2})\s+'
r'(\d{1,2}(?:\.\d+)?)\s+'
r'([NS])\s+'
r'(\d{1,3})\s+'
r'(\d{1,2})\s+'
r'(\d{1,2}(?:\.\d+)?)\s+'
r'([EW])\s+'
r'(-?\d+(?:\.\d+)?)m'
r'(?:\s+(\d+(?:\.\d+)?)m'
r'(?:\s+(\d+(?:\.\d+)?)m'
r'(?:\s+(\d+(?:\.\d+)?)m)?'
r')?)?$',
re.DOTALL
)
m = pattern.match(inp)
if not m:
return False
lat_deg = int(m.group(1))
lat_min = int(m.group(2))
lat_sec = float(m.group(3))
lon_deg = int(m.group(5))
lon_min = int(m.group(6))
lon_sec = float(m.group(7))
if lat_deg > 90: return False
if lat_min > 59: return False
if lat_sec >= 60: return False
if lon_deg > 180: return False
if lon_min > 59: return False
if lon_sec >= 60: return False
return inp
def validate_dns_sshfp(inp):
"""Replicates Validate::validateDnsSshfp from the patch."""
parts = inp.strip().split()
if len(parts) != 3:
return False
algorithm, fp_type, fingerprint = parts
valid_algorithms = [1, 2, 3, 4, 6]
if not algorithm.isdigit() or int(algorithm) not in valid_algorithms:
return False
valid_types = [1, 2]
if not fp_type.isdigit() or int(fp_type) not in valid_types:
return False
if not all(c in string.hexdigits for c in fingerprint):
return False
fp_type_int = int(fp_type)
expected = {1: 40, 2: 64}.get(fp_type_int, 0)
if len(fingerprint) != expected:
return False
return inp
def validate_dns_tlsa(inp):
"""Replicates Validate::validateDnsTlsa from the patch."""
parts =…
- Record
GHSA-j6fm-9rfm-j5hx- CVSS 4.0
- 8.6 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-74
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
froxlor/froxlorPackagist |
through 2.3.6 | 2.3.7 |
froxlor/froxlorPackagist |
before 2.3.7, plus listed versions 0.10.00.10.0-rc10.10.0-rc20.10.10.10.10 Show 45 moreShow less0.10.110.10.120.10.130.10.140.10.150.10.160.10.170.10.180.10.190.10.20.10.200.10.210.10.220.10.230.10.23.10.10.240.10.250.10.260.10.270.10.280.10.290.10.29.10.10.30.10.300.10.310.10.320.10.330.10.340.10.34.10.10.350.10.35.10.10.360.10.370.10.380.10.38.10.10.38.20.10.38.30.10.40.10.50.10.60.10.70.10.80.10.92.0.02.0.1 |
2.3.7 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-41237 is a high vulnerability (CVSS 8.6) in Froxlor, published May 29, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.27%, the 19th percentile. Fixed in froxlor/froxlor 2.3.7.
References
github.com/froxlor/froxlor/security/advisories/GHSA-j6fm-9rfm-j5hx
github.com/froxlor/froxlor/commit/b34829262dc3
github.com/froxlor/froxlor/releases/tag/2.3.7
nvd.nist.gov/vuln/detail/CVE-2026-30932
nvd.nist.gov/vuln/detail/CVE-2026-41237
github.com/advisories/GHSA-j6fm-9rfm-j5hx
github.com/CVEProject/cvelistV5/tree/main/cves/2026/41xxx/CVE-2026-41237.json
github.com/froxlor/froxlor
Left out here: 58 versions and the rest of 2 source descriptions. The JSON record has them.