MLeap LeapFrame JSON tensor dimension-check bypass PoC (source-verified)

Proof-of-concept material for a huntr Model Format Vulnerability report against combust/mleap (mleap-tensor/src/main/scala/ml/combust/mleap/tensor/{Tensor,JsonSupport}.scala).

The bug, verified against the live source fetched directly today

The normal, safe construction path, Tensor.create() (Tensor.scala:23-35), calls normalizeDimensions() (Tensor.scala:51-64), which throws IllegalArgumentException if normalizedDimensions.product != size (the values array's real length).

The JSON deserialization path bypasses this entirely:

// JsonSupport.scala:30-31 (current source)
implicit def mleapDenseTensorFormat[T: JsonFormat: ClassTag]: RootJsonFormat[DenseTensor[T]] =
  jsonFormat[Array[T], Seq[Int], DenseTensor[T]](DenseTensor[T], "values", "dimensions")
implicit def mleapSparseTensorFormat[T: JsonFormat: ClassTag]: RootJsonFormat[SparseTensor[T]] =
  jsonFormat[Seq[Seq[Int]], Array[T], Seq[Int], SparseTensor[T]](SparseTensor[T], "indices", "values", "dimensions")

These call the DenseTensor/SparseTensor case-class constructors directly, never going through Tensor.create/normalizeDimensions - so a tiny, internally-inconsistent JSON cell like evil_leapframe_cell.json (dimensions claim 2,000,000,000 elements; only 1 real value/index present) parses without any error.

The inconsistency only becomes dangerous later, when downstream code calls .toArray/.toDense on the tensor (Tensor.scala:135, new Array[T](dimensions.product)) - dimensions.product is computed as Int (not Long), so the allocation attempt is capped near 2^31 elements (~17GB for Double), and many combinations overflow Int into a negative number, raising NegativeArraySizeException rather than a truly unbounded allocation.

Reachable from an untrusted .json LeapFrame via the public FrameReader/DefaultFrameReader API, and unauthenticated via JsonScoringController.scala:80 in the mleap-spring-boot serving stack.

Honest limits and duplicate risk (disclosed plainly, not hidden)

No JVM/Scala toolchain was available on this host to build/run mleap and trigger this live - confidence rests on direct reading of the current source for both the safe path (Tensor.create) and the bypass path (JsonSupport's direct constructors), not a live crash.

Real, unresolved duplicate risk: combust/mleap issue #897, "Security vulnerabilities in MLeap serving stack - requesting private reporting channel" (opened by a third-party researcher, still open, content kept private per their own request), states verbatim: "I've identified multiple security vulnerabilities in the MLeap serving modules (mleap-spring-boot, mleap-executor, mleap-grpc-server)... These include issues that allow unauthenticated remote callers to crash the service and influence server-side network behavior." This overlaps in target (mleap-spring-boot, unauthenticated crash) with the reachability path described above, but the issue's technical content is private, so overlap with this specific bug cannot be confirmed or ruled out from the public record. Disclosed here explicitly so the triager can check for duplication against #897 directly.

Impact: Denial of Service (allocation failure/exception, not a heap overflow given the Int-bounded product) via an internally-inconsistent tensor cell in an untrusted LeapFrame JSON file, reachable unauthenticated through the serving stack.

Suggested fix: Route JSON deserialization through Tensor.create() (or call normalizeDimensions/an equivalent consistency check directly) instead of constructing DenseTensor/SparseTensor via their raw case-class constructors.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support