diff --git a/src/main/java/com/launchdarkly/sdk/server/integrations/FileDataSourceParsing.java b/src/main/java/com/launchdarkly/sdk/server/integrations/FileDataSourceParsing.java index 03bfd3676..242788f9a 100644 --- a/src/main/java/com/launchdarkly/sdk/server/integrations/FileDataSourceParsing.java +++ b/src/main/java/com/launchdarkly/sdk/server/integrations/FileDataSourceParsing.java @@ -10,7 +10,9 @@ import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.ItemDescriptor; import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.representer.Representer; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -149,7 +151,8 @@ public FlagFileRep parseJson(JsonElement tree) throws FileDataException, IOExcep * */ static final class YamlFlagFileParser extends FlagFileParser { - private static final Yaml yaml = new Yaml(); + private static final Yaml yaml = new Yaml(new SafeConstructor(), new Representer()); + // Using SafeConstructor disables instantiation of arbitrary classes - https://github.com/launchdarkly/java-server-sdk/issues/288 private static final Gson gson = new Gson(); private static final JsonFlagFileParser jsonFileParser = new JsonFlagFileParser(); diff --git a/src/test/java/com/launchdarkly/sdk/server/integrations/FileDataSourceTest.java b/src/test/java/com/launchdarkly/sdk/server/integrations/FileDataSourceTest.java index e27e96882..144af1a42 100644 --- a/src/test/java/com/launchdarkly/sdk/server/integrations/FileDataSourceTest.java +++ b/src/test/java/com/launchdarkly/sdk/server/integrations/FileDataSourceTest.java @@ -8,6 +8,7 @@ import com.launchdarkly.sdk.server.interfaces.DataSource; import com.launchdarkly.sdk.server.interfaces.DataSourceStatusProvider; import com.launchdarkly.sdk.server.interfaces.DataStore; +import com.launchdarkly.testhelpers.TempFile; import org.junit.Test; @@ -29,6 +30,7 @@ import static com.launchdarkly.sdk.server.integrations.FileDataSourceTestData.resourceFilePath; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; @SuppressWarnings("javadoc") @@ -142,4 +144,28 @@ private void verifyUnsuccessfulStart(DataSource fp) { DataSourceStatusProvider.Status status = requireDataSourceStatus(statuses, DataSourceStatusProvider.State.INITIALIZING); assertEquals(DataSourceStatusProvider.ErrorKind.INVALID_DATA, status.getLastError().getKind()); } + + @Test + public void instantiationOfArbitraryTypeIsNotAllowed() throws Exception { + // test for https://nvd.nist.gov/vuln/detail/CVE-2022-1471 - this test fails if we use the + // empty Yaml() constructor in FileDataSourceParsing + String className = SimulatedMaliciousType.class.getName(); + Class.forName(this.getClass().getName()); + Class.forName(className); + try (TempFile f = TempFile.create()) { + f.setContents("---\nbad_thing: !!" + className + " [value]\n"); + try (DataSource fp = makeDataSource(FileData.dataSource().filePaths(f.getPath()))) { + verifyUnsuccessfulStart(fp); + assertThat(SimulatedMaliciousType.wasInstantiated, is(false)); + } + } + } + + public static class SimulatedMaliciousType { + static volatile boolean wasInstantiated = false; + + public SimulatedMaliciousType(String value) { + wasInstantiated = true; + } + } }