VYPR
Critical severityNVD Advisory· Published Jan 22, 2024· Updated Nov 3, 2025

CVE-2017-20189

CVE-2017-20189

Description

In Clojure before 1.9.0, classes can be used to construct a serialized object that executes arbitrary code upon deserialization. This is relevant if a server deserializes untrusted objects.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Clojure before 1.9.0 allows deserialization of untrusted data to execute arbitrary code via a gadget chain using proxy classes.

Vulnerability

Overview

CVE-2017-20189 describes a deserialization vulnerability in the Clojure programming language affecting versions prior to 1.9.0. The root cause is that Clojure's proxy mechanism allowed generated proxy classes to be serialized and deserialized. An attacker can construct a serialized object that, when deserialized by a server with Clojure on the classpath, triggers arbitrary code execution through a gadget chain [1][2][3].

Exploitation

Exploitation requires an application that deserializes untrusted data, with Clojure libraries present on the classpath (regardless of whether the application actively uses Clojure). No authentication is needed if the deserialization endpoint is exposed to an attacker. The gadget chain leverages Java serialization and Clojure-specific classes to execute arbitrary code upon deserialization [3].

Impact

A successful attack results in remote code execution (RCE) with the privileges of the application performing deserialization. This can lead to full system compromise, data exfiltration, or further lateral movement within the network. The vulnerability is particularly dangerous because Clojure may be a dependency even in non-Clojure applications [2][3].

Mitigation

The vulnerability is fixed in Clojure 1.9.0. The fix prevented serialization of proxy classes by having writeObject and readObject methods throw NotSerializableException for proxy classes, effectively disabling the gadget chain [4]. Users should upgrade to Clojure 1.9.0 or later. As a general security measure, applications should avoid deserializing untrusted data or use safe deserialization practices [1][2][3].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.clojure:clojureMaven
< 1.9.01.9.0

Affected products

2

Patches

1
271674c9b484

CLJ-2204 Disable serialization of proxy classes

https://github.com/clojure/clojureChouserJul 18, 2017via ghsa
2 files changed · +49 2
  • src/clj/clojure/core_proxy.clj+19 1 modified
    @@ -13,6 +13,7 @@
     (import
      '(clojure.asm ClassWriter ClassVisitor Opcodes Type) 
      '(java.lang.reflect Modifier Constructor)
    + '(java.io Serializable NotSerializableException)
      '(clojure.asm.commons Method GeneratorAdapter)
      '(clojure.lang IProxy Reflector DynamicClassLoader IPersistentMap PersistentHashMap RT))
     
    @@ -44,7 +45,8 @@
     
     (defn- generate-proxy [^Class super interfaces]
       (let [cv (new ClassWriter (. ClassWriter COMPUTE_MAXS))
    -        cname (.replace (proxy-name super interfaces) \. \/) ;(str "clojure/lang/" (gensym "Proxy__"))
    +        pname (proxy-name super interfaces)
    +        cname (.replace pname \. \/) ;(str "clojure/lang/" (gensym "Proxy__"))
             ctype (. Type (getObjectType cname))
             iname (fn [^Class c] (.. Type (getType c) (getInternalName)))
             fmap "__clojureFnMap"
    @@ -148,6 +150,22 @@
                 
                 (. gen (returnValue))
                 (. gen (endMethod)))))
    +                                        ;disable serialization
    +    (when (some #(isa? % Serializable) (cons super interfaces))
    +      (let [m (. Method (getMethod "void writeObject(java.io.ObjectOutputStream)"))
    +            gen (new GeneratorAdapter (. Opcodes ACC_PRIVATE) m nil nil cv)]
    +        (. gen (visitCode))
    +        (. gen (loadThis))
    +        (. gen (loadArgs))
    +        (. gen (throwException (totype NotSerializableException) pname))
    +        (. gen (endMethod)))
    +      (let [m (. Method (getMethod "void readObject(java.io.ObjectInputStream)"))
    +            gen (new GeneratorAdapter (. Opcodes ACC_PRIVATE) m nil nil cv)]
    +        (. gen (visitCode))
    +        (. gen (loadThis))
    +        (. gen (loadArgs))
    +        (. gen (throwException (totype NotSerializableException) pname))
    +        (. gen (endMethod))))
                                             ;add IProxy methods
         (let [m (. Method (getMethod "void __initClojureFnMappings(clojure.lang.IPersistentMap)"))
               gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
    
  • test/clojure/test_clojure/java_interop.clj+30 1 modified
    @@ -10,7 +10,8 @@
     
     
     (ns clojure.test-clojure.java-interop
    -  (:use clojure.test))
    +  (:use clojure.test)
    +  (:require [clojure.inspector]))
     
     ; http://clojure.org/java_interop
     ; http://clojure.org/compilation
    @@ -171,6 +172,34 @@
             "chain chain chain")))
     
     
    +;; serialized-proxy can be regenerated using a modified version of
    +;; Clojure with the proxy serialization prohibition disabled and the
    +;; following code:
    +#_(let [baos (java.io.ByteArrayOutputStream.) ]
    +    (with-open [baos baos]
    +      (.writeObject (java.io.ObjectOutputStream. baos) (clojure.inspector/list-model nil)))
    +    (println (apply str (for [c (String. (.toByteArray baos) "ISO-8859-1")]
    +                          (if (<= 32 (int c) (int \z)) c (format "\\%03o" (int c)))))))
    +(def serialized-proxy "\254\355\000\005sr\000Eclojure.inspector.proxy$javax.swing.table.AbstractTableModel$ff19274art\330\266_\010ME\002\000\001L\000\016__clojureFnMapt\000\035Lclojure/lang/IPersistentMap;xr\000$javax.swing.table.AbstractTableModelr\313\3538\256\001\377\276\002\000\001L\000\014listenerListt\000%Ljavax/swing/event/EventListenerList;xpsr\000#javax.swing.event.EventListenerList\2616\306\175\204\352\326D\003\000\000xppxsr\000\037clojure.lang.PersistentArrayMap\3437p\017\230\305\364\337\002\000\002L\000\005_metaq\000\176\000\001[\000\005arrayt\000\023[Ljava/lang/Object;xr\000\033clojure.lang.APersistentMap]\174/\003t r\173\002\000\002I\000\005_hashI\000\007_hasheqxp\000\000\000\000\000\000\000\000pur\000\023[Ljava.lang.Object;\220\316X\237\020s)l\002\000\000xp\000\000\000\006t\000\016getColumnCountsr\000%clojure.inspector$list_model$fn__8816H\252\320\325b\371!+\002\000\000xr\000\026clojure.lang.AFunction>\006p\234\236F\375\313\002\000\001L\000\021__methodImplCachet\000\036Lclojure/lang/MethodImplCache;xppt\000\013getRowCountsr\000%clojure.inspector$list_model$fn__8818-\037I\247\234/U\226\002\000\001L\000\005nrowst\000\022Ljava/lang/Object;xq\000\176\000\017ppt\000\012getValueAtsr\000%clojure.inspector$list_model$fn__8820\323\331\174ke\233\370\034\002\000\002L\000\011get_labelq\000\176\000\024L\000\011get_valueq\000\176\000\024xq\000\176\000\017ppp")
    +
    +(deftest test-proxy-non-serializable
    +  (testing "That proxy classes refuse serialization and deserialization"
    +    ;; Serializable listed directly in interface list:
    +    (is (thrown? java.io.NotSerializableException
    +                 (-> (java.io.ByteArrayOutputStream.)
    +                     (java.io.ObjectOutputStream.)
    +                     (.writeObject (proxy [Object java.io.Serializable] [])))))
    +    ;; Serializable included via inheritence:
    +    (is (thrown? java.io.NotSerializableException
    +                 (-> (java.io.ByteArrayOutputStream.)
    +                     (java.io.ObjectOutputStream.)
    +                     (.writeObject (clojure.inspector/list-model nil)))))
    +    ;; Deserialization also prohibited:
    +    (is (thrown? java.io.NotSerializableException
    +                 (-> serialized-proxy (.getBytes "ISO-8859-1")
    +                     java.io.ByteArrayInputStream. java.io.ObjectInputStream.
    +                     .readObject)))))
    +
     (deftest test-bases
       (are [x y] (= x y)
           (bases java.lang.Math)
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.