Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360
ZeroDays CVE-2025-30007
High CVE-2025-30007 CVSS 8.8 HestiaCP Bash

HestiaCP DNS Record OS Command Injection

CVE-2025-30007: Authenticated OS command injection in HestiaCP's DNS record handling lets low-privilege users execute arbitrary commands as root.

Offensive360 Research Team
Affects: < 1.9.5
Source Code View Patch

Overview

CVE-2025-30007 is an authenticated OS command injection vulnerability in HestiaCP, a popular open-source web hosting control panel. The flaw resides in the DNS record management subsystem, specifically in the interaction between is_dns_record_format_valid() — the function responsible for validating DNS record type input — and update_domain_zone(), which processes and writes zone data using an eval-based variable assignment. A low-privilege authenticated user (any account with DNS management access) can inject a single-quote character into the DNS record type field, prematurely terminating a shell string context and appending arbitrary commands that execute as root.

The vulnerability was identified in HestiaCP versions prior to 1.9.5 and was addressed in the patch released under that version. Because HestiaCP runs its backend administrative scripts with elevated privileges to manage system-level resources such as DNS zones and web server configurations, successful exploitation results in complete host compromise — not merely control-panel takeover.

The affected surface is particularly dangerous in multi-tenant environments. Web hosting providers operating HestiaCP on shared infrastructure expose all co-hosted clients to full compromise if any single low-privilege account is obtained or created by an attacker. This elevates the practical risk beyond the 8.8 CVSS score in many real-world deployments.

Technical Analysis

The root cause is a two-component failure: inadequate input sanitization in the validation layer and unsafe dynamic code execution via eval in the processing layer.

Component 1: Insufficient validation in is_dns_record_format_valid()

The validation function checks the DNS record type against an expected format but does not strip or reject shell metacharacters, including the single-quote ('). The logic is essentially an allowlist check on the record type string, but it does not account for characters that are meaningful in a Bash string context. A value like A'; id # passes through validation because the function focuses on the alphanumeric record type token rather than treating the full string as potentially hostile shell input.

Component 2: Unsafe eval-based parsing in update_domain_zone()

The zone update function constructs a shell variable assignment string and passes it to eval to dynamically set variables during DNS record processing. The pattern resembles the following vulnerable construct:

# VULNERABLE: eval used to assign user-controlled record type to a variable
build_dns_record() {
    local record_type="$1"
    local record_value="$2"

    # Validation passes for input like: A'; malicious_command #
    if ! is_dns_record_format_valid "$record_type"; then
        echo "Error: invalid record type"
        return 1
    fi

    # eval interprets the record_type string as shell code.
    # If record_type = "A'; id #", the eval expands to:
    #   RECORD_TYPE='A'; id #'
    # which executes `id` (or any command) as root.
    eval "RECORD_TYPE='$record_type'"

    update_domain_zone "$RECORD_TYPE" "$record_value"
}

When eval receives RECORD_TYPE='A'; id #', the shell parser sees two complete statements:

  1. RECORD_TYPE='A' — a benign variable assignment.
  2. id #' — an arbitrary command, with the trailing single-quote treated as a comment or unclosed string that Bash handles gracefully in non-interactive mode.

Because the HestiaCP backend runs with root privileges to manage system DNS configuration, the injected command inherits those privileges. The attacker gains a root shell in a single API call or form submission — no chaining, no further privilege escalation required.

The exploitation path is direct: authenticate as any user with DNS management rights, navigate to the DNS record creation interface or invoke the corresponding CLI/API endpoint, supply a crafted record type value containing '; <payload> #, and observe command execution in the context of the root process.

Impact

An attacker who exploits CVE-2025-30007 achieves arbitrary OS command execution as root on the underlying host. From that position, the following consequences are realistic and immediate:

  • Full host takeover: Read, modify, or delete any file on the system, including private keys, database credentials, and customer data.
  • Persistence: Install backdoors, SSH authorized keys, or cron-based persistence mechanisms that survive control panel updates.
  • Lateral movement: In shared hosting environments, access all co-hosted domains, email data, and databases belonging to other customers.
  • Credential harvesting: Extract HestiaCP admin credentials, database root passwords, and SSL private keys stored on the filesystem.
  • Ransomware or data destruction: As root, an attacker can encrypt or wipe all hosted data.

The CVSS 8.8 score reflects the High severity with a network attack vector, low attack complexity, low privileges required, and no user interaction needed beyond the attacker’s own authenticated session. The confidentiality, integrity, and availability impacts are all rated High. In practice, the “low privileges required” condition means any registered hosting account — which may cost nothing or be obtained through social engineering — is sufficient to trigger root code execution.

How to Fix It

Upgrade immediately. The canonical remediation is to update HestiaCP to version 1.9.5 or later:

# Update HestiaCP via the built-in upgrade mechanism
apt-get update && apt-get upgrade hestia
# Or use the HestiaCP CLI upgrade
v-update-sys-hestia

The patch eliminates the eval-based variable assignment and replaces it with direct variable assignment, removing the shell interpretation step entirely. It also strengthens is_dns_record_format_valid() to reject inputs containing shell metacharacters. The corrected pattern looks like this:

# FIXED: No eval. Direct assignment with strict allowlist validation.
build_dns_record() {
    local record_type="$1"
    local record_value="$2"

    # Strict allowlist: only permit known DNS record type strings.
    # Reject anything containing characters outside [A-Za-z0-9].
    if [[ ! "$record_type" =~ ^(A|AAAA|CNAME|MX|TXT|NS|SRV|CAA|PTR)$ ]]; then
        echo "Error: invalid or disallowed record type"
        return 1
    fi

    # Safe: RECORD_TYPE is set directly, never passed to eval.
    RECORD_TYPE="$record_type"

    update_domain_zone "$RECORD_TYPE" "$record_value"
}

Key remediation principles applied here:

  1. Eliminate eval for user-controlled input — there is no safe way to pass unsanitized user data to eval.
  2. Use strict allowlist regex matching only the exact set of valid DNS record type strings.
  3. Apply validation as close to the data source as possible, before the value is used in any further processing context.

Our Take

This vulnerability is a textbook example of why eval should be treated as a last resort in shell scripting, never as a convenience. The pattern of using eval to dynamically construct variable assignments from user input is a recurring antipattern in shell-heavy infrastructure tools, and it consistently produces exploitable injection conditions. The fact that validation existed — but was insufficient — illustrates a common architectural mistake: treating validation and safe handling as separable concerns. Even a passing validation check cannot compensate for a fundamentally unsafe execution primitive downstream.

For enterprises running hosting infrastructure on HestiaCP or similar control panels, this class of vulnerability is particularly consequential. Control panels are attractive targets precisely because they aggregate privileged access to many resources in one place. A single low-value compromised account can pivot to complete infrastructure ownership.

From a defense-in-depth standpoint, running control panel backend processes with the minimum privilege necessary — and auditing every path that reaches root execution — would contain the blast radius even when injection vulnerabilities exist.

Detection with SAST

SAST analysis for this vulnerability class targets two complementary patterns:

Pattern 1 — Taint tracking through eval: Any data flow where user-controlled input (sourced from HTTP parameters, CLI arguments, API fields, or environment variables) reaches an eval statement without passing through a strict allowlist or escaping function. This maps to CWE-78 (OS Command Injection) and CWE-77 (Command Injection). Offensive360’s SAST engine models eval as a high-risk sink and traces all data flows from external input sources to that sink, flagging cases where no sanitization barrier exists on the path.

Pattern 2 — Insufficient allowlist validation: Cases where a validation function is present but uses weak matching (substring checks, type-only checks, or regex that permits metacharacters). The engine flags validation functions whose output does not include a reject-all-else case for non-matching input, and specifically checks whether shell metacharacters (', ", ;, $, `, \) are excluded from the accepted character set.

For Bash and shell script codebases specifically, Offensive360’s rules flag:

  • Any eval "...$VAR..." or eval "...$VAR..." construct where VAR traces to external input.
  • String interpolation into eval arguments without prior printf '%q' escaping or equivalent.
  • Validation functions that return success for inputs containing ['";\$]`.

The relevant CWE taxonomy: CWE-78, CWE-77, CWE-20 (Improper Input Validation), and CWE-269 (Improper Privilege Management) for the root execution context.

References

#command-injection #dns #privilege-escalation #bash

Detect this vulnerability class in your codebase

Offensive360 SAST scans your source code for CVE-2025-30007-class vulnerabilities and thousands of other patterns — across 60+ languages.