Skip to main content
CVE Vulnerability Database

CVE-2024-5979: H2o H2o Denial of Service Vulnerability

CVE-2024-5979 is a denial of service vulnerability in H2o H2o 3.46.0 where the run_tool command allows arbitrary class execution, causing server crashes. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2024-5979 Overview

CVE-2024-5979 is a denial of service vulnerability in h2oai/h2o-3 version 3.46.0. The run_tool command in the rapids component allows invocation of the main function of any class under the water.tools namespace. One such class, MojoConvertTool, terminates the JVM through System.exit when it receives insufficient or invalid arguments. An unauthenticated remote attacker can trigger this code path over the network and crash the H2O server process. The issue is classified under [CWE-94] (Improper Control of Generation of Code) and carries a CVSS 3.0 score of 7.5 with an availability-only impact.

Critical Impact

Unauthenticated attackers can remotely crash H2O-3 machine learning server instances by invoking MojoConvertTool through the run_tool Rapids command with invalid arguments.

Affected Products

  • H2O h2o-3 version 3.46.0
  • Components: h2o-core (water.rapids.ast.prims.internal.AstRunTool)
  • Components: h2o-algos (water.tools.MojoConvertTool)

Discovery Timeline

  • 2024-06-27 - CVE CVE-2024-5979 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2024-5979

Vulnerability Analysis

H2O-3 exposes a Rapids expression language endpoint that includes a run_tool primitive. This primitive is implemented in AstRunTool and uses Java reflection to load a class from the water.tools package and invoke its main(String[]) method. The allowlist is limited to the water.tools namespace, but any tool in that namespace with a strict main method becomes reachable.

MojoConvertTool.main validated its arguments and then called System.exit(1) or System.exit(2) when arguments were missing or when the MOJO file did not exist. Because the tool runs inside the H2O JVM, System.exit terminates the entire server, not just the request handler. Any unauthenticated caller who can reach the Rapids interface can therefore stop the service.

Root Cause

The root cause is unsafe reflective dispatch to a CLI entry point that assumes process ownership. Command line utilities are designed to end the process on error. Exposing their main methods through a network-reachable dispatcher lets remote input control JVM lifecycle. Argument validation errors and file existence checks were both wired to System.exit rather than to exception-based error handling.

Attack Vector

An attacker sends a Rapids expression to the H2O-3 REST API that invokes run_tool with MojoConvertTool and fewer than two arguments, or with a path that does not resolve to a file. MojoConvertTool.main prints usage and calls System.exit, which kills the H2O worker. No authentication, privileges, or user interaction are required.

java
// Patch: h2o-algos/src/main/java/water/tools/MojoConvertTool.java
// Replaces System.exit with IllegalArgumentException so callers can handle errors
     Files.write(pojoPath, pojo.getBytes(StandardCharsets.UTF_8));
 }

-    private static void usage() {
-        System.err.println("java -cp h2o.jar " + MojoConvertTool.class.getName() + " source_mojo.zip target_pojo.java");
-    }
-
     public static void main(String[] args) throws IOException {
-        if (args.length < 2) {
-            usage();
+        try {
+            mainInternal(args);
+        }
+        catch (IllegalArgumentException e) {
+            System.err.println(e.getMessage());
             System.exit(1);
         }
+    }
+
+    public static void mainInternal(String[] args) throws IOException {
+        if (args.length < 2 || args[0] == null || args[1] == null) {
+            throw new IllegalArgumentException("java -cp h2o.jar " + MojoConvertTool.class.getName() + " source_mojo.zip target_pojo.java");
+        }

     File mojoFile = new File(args[0]);
-    if (!mojoFile.isFile()) {
-        System.err.println("Specified MOJO file (" + mojoFile.getAbsolutePath() + ") doesn't exist!");
-        System.exit(2);
+    if (!mojoFile.exists() || !mojoFile.isFile()) {
+        throw new IllegalArgumentException("Specified MOJO file (" + mojoFile.getAbsolutePath() + ") doesn't exist!");

Source: h2oai/h2o-3 commit d0899f8

Detection Methods for CVE-2024-5979

Indicators of Compromise

  • Unexpected termination of the H2O-3 JVM process with exit code 1 or 2 without an accompanying stack trace or OOM event.
  • Rapids API requests containing the string run_tool combined with MojoConvertTool or other water.tools class names.
  • Repeated H2O cluster restarts correlated with inbound requests to the Rapids endpoint from external or untrusted sources.

Detection Strategies

  • Inspect HTTP request bodies to the H2O-3 REST API for Rapids expressions that reference run_tool and any water.tools.* class.
  • Alert on H2O server exit events not preceded by a graceful shutdown command from an authorized operator.
  • Baseline normal Rapids usage in the environment and flag any invocation of run_tool, which is rarely used in typical model training workflows.

Monitoring Recommendations

  • Forward H2O-3 stdout, stderr, and process supervisor logs to a central logging platform to correlate crashes with request activity.
  • Monitor network access to the H2O-3 listener (default TCP 54321) and restrict source addresses at the network layer.
  • Track EPSS movement for CVE-2024-5979, currently 0.787% at the 51.754 percentile, to adjust prioritization as exploit likelihood changes.

How to Mitigate CVE-2024-5979

Immediate Actions Required

  • Upgrade H2O-3 to a build that contains the fix from commit d0899f8e0f7a584b60405a65b1d7b439aaaa55a5, which routes tool errors through exceptions instead of System.exit.
  • Restrict network access to the H2O-3 REST API so that only trusted data science workstations and orchestration systems can reach it.
  • Require authentication on the H2O-3 cluster using the built-in Kerberos, LDAP, or hash-file authentication options.

Patch Information

The upstream fix is tracked in pull request #16366 ([GH-16351] Do not call System.exit from water.tools). MojoConvertTool now exposes a mainInternal method that throws IllegalArgumentException on bad input, and AstRunTool was updated to invoke mainInternal via reflection instead of main. See the h2oai/h2o-3 commit d0899f8 and the Huntr bounty report for full details.

Workarounds

  • Place H2O-3 behind a reverse proxy that blocks or rewrites Rapids expressions containing run_tool.
  • Run the H2O-3 process under a supervisor such as systemd with automatic restart so that crashes reduce, but do not eliminate, service downtime.
  • Isolate H2O-3 nodes on a dedicated internal network segment with egress and ingress filtering.
bash
# Example iptables rule limiting H2O-3 REST access to a trusted subnet
iptables -A INPUT -p tcp --dport 54321 -s 10.10.0.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 54321 -j DROP

# Example nginx location block dropping Rapids run_tool requests
location /3/Rapids {
    if ($request_body ~* "run_tool") { return 403; }
    proxy_pass http://h2o_backend;
}

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.