CVE-2020-1953
Description
Apache Commons Configuration <=2.6 allows remote code execution via untrusted YAML files due to default SnakeYAML deserialization enabled.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Apache Commons Configuration <=2.6 allows remote code execution via untrusted YAML files due to default SnakeYAML deserialization enabled.
This vulnerability in Apache Commons Configuration versions 2.2 through 2.6 allows an attacker to achieve remote code execution if the application loads a YAML configuration file from an untrusted source. The root cause is that the library uses SnakeYAML for YAML parsing and does not override the default constructor, which permits arbitrary Java object instantiation via YAML tags (e.g., !!javax.script.ScriptEngineManager). The fix introduces a createYamlForReading() method that uses a restricted Constructor to prevent such deserialization attacks [1][2].
The attack surface is limited to scenarios where a crafted YAML file is loaded. No authentication is required for the file load itself, but the attacker must first be able to supply a malicious YAML file to the application (e.g., via upload, network share, or a compromised upstream data source). When the configuration is parsed, SnakeYAML processes inline !! tags and instantiates the specified classes, which can trigger code execution via gadget chains present on the classpath [2]. The exploit does not rely on any user interaction beyond the file being loaded.
Successful exploitation gives the attacker arbitrary code execution in the context of the Java application. This can lead to full system compromise, including data exfiltration, lateral movement, or installation of malware. The vulnerability has been assigned a CVSS v3 score of 9.8 (Critical) because it requires no privileges and no user interaction [2].
A patch was applied in commit add7375cf37fd316d4838c6c56b054fc293b4641, which restricts the YAML parser to only load standard Java types and prevents arbitrary object creation. Apache Commons Configuration users should upgrade to version 2.7 or later. For those unable to upgrade, the workaround involves ensuring that only trusted sources provide YAML configuration files, or manually configuring the SnakeYAML Yaml instance with a safe Constructor [1][2].
AI Insight generated on May 21, 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.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.commons:commons-configuration2Maven | >= 2.2, < 2.7 | 2.7 |
Affected products
2- Range: 2.2
Patches
1add7375cf37fPrevent object creation when loading YAML files.
2 files changed · +87 −7
src/main/java/org/apache/commons/configuration2/YAMLConfiguration.java+37 −4 modified@@ -18,11 +18,14 @@ package org.apache.commons.configuration2; import org.apache.commons.configuration2.ex.ConfigurationException; +import org.apache.commons.configuration2.ex.ConfigurationRuntimeException; import org.apache.commons.configuration2.io.InputStreamSupport; import org.apache.commons.configuration2.tree.ImmutableNode; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.representer.Representer; import java.io.IOException; import java.io.InputStream; @@ -65,7 +68,7 @@ public void read(final Reader in) throws ConfigurationException { try { - final Yaml yaml = new Yaml(); + final Yaml yaml = createYamlForReading(new LoaderOptions()); final Map<String, Object> map = (Map) yaml.load(in); load(map); } @@ -80,7 +83,7 @@ public void read(final Reader in, final LoaderOptions options) { try { - final Yaml yaml = new Yaml(options); + final Yaml yaml = createYamlForReading(options); final Map<String, Object> map = (Map) yaml.load(in); load(map); } @@ -117,7 +120,7 @@ public void read(final InputStream in) throws ConfigurationException { try { - final Yaml yaml = new Yaml(); + final Yaml yaml = createYamlForReading(new LoaderOptions()); final Map<String, Object> map = (Map) yaml.load(in); load(map); } @@ -132,7 +135,7 @@ public void read(final InputStream in, final LoaderOptions options) { try { - final Yaml yaml = new Yaml(options); + final Yaml yaml = createYamlForReading(options); final Map<String, Object> map = (Map) yaml.load(in); load(map); } @@ -142,4 +145,34 @@ public void read(final InputStream in, final LoaderOptions options) } } + /** + * Creates a {@code Yaml} object for reading a Yaml file. The object is + * configured with some default settings. + * + * @param options options for loading the file + * @return the {@code Yaml} instance for loading a file + */ + private static Yaml createYamlForReading(LoaderOptions options) + { + return new Yaml(createClassLoadingDisablingConstructor(), new Representer(), new DumperOptions(), options); + } + + /** + * Returns a {@code Constructor} object for the YAML parser that prevents + * all classes from being loaded. This effectively disables the dynamic + * creation of Java objects that are declared in YAML files to be loaded. + * + * @return the {@code Constructor} preventing object creation + */ + private static Constructor createClassLoadingDisablingConstructor() + { + return new Constructor() + { + @Override + protected Class<?> getClassForName(String name) + { + throw new ConfigurationRuntimeException("Class loading is disabled."); + } + }; + } }
src/test/java/org/apache/commons/configuration2/TestYAMLConfiguration.java+50 −3 modified@@ -17,26 +17,37 @@ package org.apache.commons.configuration2; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - +import java.io.ByteArrayInputStream; +import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.io.StringReader; import java.io.StringWriter; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; import java.util.Map; import org.apache.commons.configuration2.ex.ConfigurationException; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.yaml.snakeyaml.Yaml; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + /** * Unit test for {@link YAMLConfiguration} */ public class TestYAMLConfiguration { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + /** The files that we test with. */ private final String testYaml = ConfigurationAssert.getTestFile("test.yaml").getAbsolutePath(); @@ -134,4 +145,40 @@ public void testCopyConstructor() yamlConfiguration = new YAMLConfiguration(c); assertEquals("bar", yamlConfiguration.getString("foo")); } + + @Test + public void testObjectCreationFromReader() + { + final File createdFile = new File(temporaryFolder.getRoot(), "data.txt"); + final String yaml = "!!java.io.FileOutputStream [" + createdFile.getAbsolutePath() + "]"; + + try + { + yamlConfiguration.read(new StringReader(yaml)); + fail("Loading configuration did not cause an exception!"); + } + catch (ConfigurationException e) + { + //expected + } + assertFalse("Java object was created", createdFile.exists()); + } + + @Test + public void testObjectCreationFromStream() + { + final File createdFile = new File(temporaryFolder.getRoot(), "data.txt"); + final String yaml = "!!java.io.FileOutputStream [" + createdFile.getAbsolutePath() + "]"; + + try + { + yamlConfiguration.read(new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + fail("Loading configuration did not cause an exception!"); + } + catch (ConfigurationException e) + { + //expected + } + assertFalse("Java object was created", createdFile.exists()); + } }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/advisories/GHSA-7qx4-pp76-vrqhghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-1953ghsaADVISORY
- github.com/apache/commons-configuration/commit/add7375cf37fd316d4838c6c56b054fc293b4641ghsaWEB
- lists.apache.org/thread.html/d0e00f2e147a9e9b13a6829133092f349b2882bf6860397368a52600%40%3Cannounce.tomcat.apache.org%3Emitrex_refsource_MISC
- lists.apache.org/thread.html/d0e00f2e147a9e9b13a6829133092f349b2882bf6860397368a52600@%3Cannounce.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r16a2e949e35780c8974cf66104e812410f3904f752df6b66bf292269%40%3Ccommits.servicecomb.apache.org%3Emitrex_refsource_MISC
- lists.apache.org/thread.html/r16a2e949e35780c8974cf66104e812410f3904f752df6b66bf292269@%3Ccommits.servicecomb.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rde2186ad6ac0d6ed8d51af7509244adcf1ce0f9a3b7e1d1dd3b64676%40%3Ccommits.camel.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/rde2186ad6ac0d6ed8d51af7509244adcf1ce0f9a3b7e1d1dd3b64676@%3Ccommits.camel.apache.org%3EghsaWEB
- www.oracle.com/security-alerts/cpuoct2020.htmlghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.