VYPR
High severityNVD Advisory· Published Aug 5, 2022· Updated Aug 3, 2024

CVE-2022-2668

CVE-2022-2668

Description

An issue was discovered in Keycloak that allows arbitrary Javascript to be uploaded for the SAML protocol mapper even if the UPLOAD_SCRIPTS feature is disabled

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.keycloak:keycloak-parentMaven
< 19.0.219.0.2

Affected products

1

Patches

1
e2ae7eef39b2

SAML javascript protocol mapper: disable uploading scripts through admin console by default (#14296)

https://github.com/keycloak/keycloakMarek PosoldaSep 9, 2022via ghsa
9 files changed · +269 6
  • core/src/main/java/org/keycloak/representations/provider/ScriptProviderDescriptor.java+11 0 modified
    @@ -31,6 +31,8 @@ public class ScriptProviderDescriptor {
         public static final String POLICIES = "policies";
         public static final String MAPPERS = "mappers";
     
    +    public static final String SAML_MAPPERS = "saml-mappers";
    +
         private Map<String, List<ScriptProviderMetadata>> providers = new HashMap<>();
     
         @JsonUnwrapped
    @@ -54,6 +56,11 @@ public void setMappers(List<ScriptProviderMetadata> metadata) {
             providers.put(MAPPERS, metadata);
         }
     
    +    @JsonSetter(SAML_MAPPERS)
    +    public void setSAMLMappers(List<ScriptProviderMetadata> metadata) {
    +        providers.put(SAML_MAPPERS, metadata);
    +    }
    +
         public void addAuthenticator(String name, String fileName) {
             addProvider(AUTHENTICATORS, name, fileName, null);
         }
    @@ -76,4 +83,8 @@ public void addPolicy(String name, String fileName) {
         public void addMapper(String name, String fileName) {
             addProvider(MAPPERS, name, fileName, null);
         }
    +
    +    public void addSAMLMapper(String name, String fileName) {
    +        addProvider(SAML_MAPPERS, name, fileName, null);
    +    }
     }
    
  • quarkus/deployment/src/main/java/org/keycloak/quarkus/deployment/KeycloakProcessor.java+8 1 modified
    @@ -29,6 +29,7 @@
     import static org.keycloak.representations.provider.ScriptProviderDescriptor.MAPPERS;
     import static org.keycloak.representations.provider.ScriptProviderDescriptor.POLICIES;
     import static org.keycloak.quarkus.runtime.Environment.getProviderFiles;
    +import static org.keycloak.representations.provider.ScriptProviderDescriptor.SAML_MAPPERS;
     
     import javax.persistence.Entity;
     import javax.persistence.spi.PersistenceUnitTransactionType;
    @@ -91,6 +92,7 @@
     import org.keycloak.connections.jpa.JpaConnectionProvider;
     import org.keycloak.connections.jpa.JpaConnectionSpi;
     import org.keycloak.models.map.storage.jpa.JpaMapStorageProviderFactory;
    +import org.keycloak.protocol.saml.mappers.DeployedScriptSAMLProtocolMapper;
     import org.keycloak.quarkus.runtime.QuarkusProfile;
     import org.keycloak.quarkus.runtime.configuration.PersistedConfigSource;
     import org.keycloak.quarkus.runtime.configuration.QuarkusPropertiesConfigSource;
    @@ -170,6 +172,7 @@ class KeycloakProcessor {
             DEPLOYEABLE_SCRIPT_PROVIDERS.put(AUTHENTICATORS, KeycloakProcessor::registerScriptAuthenticator);
             DEPLOYEABLE_SCRIPT_PROVIDERS.put(POLICIES, KeycloakProcessor::registerScriptPolicy);
             DEPLOYEABLE_SCRIPT_PROVIDERS.put(MAPPERS, KeycloakProcessor::registerScriptMapper);
    +        DEPLOYEABLE_SCRIPT_PROVIDERS.put(SAML_MAPPERS, KeycloakProcessor::registerSAMLScriptMapper);
         }
     
         private static ProviderFactory registerScriptAuthenticator(ScriptProviderMetadata metadata) {
    @@ -184,6 +187,10 @@ private static ProviderFactory registerScriptMapper(ScriptProviderMetadata metad
             return new DeployedScriptOIDCProtocolMapper(metadata);
         }
     
    +    private static ProviderFactory registerSAMLScriptMapper(ScriptProviderMetadata metadata) {
    +        return new DeployedScriptSAMLProtocolMapper(metadata);
    +    }
    +
         @BuildStep
         FeatureBuildItem getFeature() {
             return new FeatureBuildItem("keycloak");
    @@ -660,7 +667,7 @@ private ProviderFactory createDeployableScriptProvider(JarFile jarFile, Entry<St
         }
     
         private boolean isScriptForSpi(Spi spi, String type) {
    -        if (spi instanceof ProtocolMapperSpi && MAPPERS.equals(type)) {
    +        if (spi instanceof ProtocolMapperSpi && (MAPPERS.equals(type) || SAML_MAPPERS.equals(type))) {
                 return true;
             } else if (spi instanceof PolicySpi && POLICIES.equals(type)) {
                 return true;
    
  • services/src/main/java/org/keycloak/protocol/saml/mappers/DeployedScriptSAMLProtocolMapper.java+59 0 added
    @@ -0,0 +1,59 @@
    +package org.keycloak.protocol.saml.mappers;
    +
    +import java.util.List;
    +import java.util.stream.Collectors;
    +
    +import org.keycloak.common.Profile;
    +import org.keycloak.models.ProtocolMapperModel;
    +import org.keycloak.provider.ProviderConfigProperty;
    +import org.keycloak.representations.provider.ScriptProviderMetadata;
    +
    +/**
    + * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
    + */
    +public class DeployedScriptSAMLProtocolMapper extends ScriptBasedMapper {
    +
    +    protected ScriptProviderMetadata metadata;
    +
    +    public DeployedScriptSAMLProtocolMapper(ScriptProviderMetadata metadata) {
    +        this.metadata = metadata;
    +    }
    +
    +    public DeployedScriptSAMLProtocolMapper() {
    +        // for reflection
    +    }
    +
    +    @Override
    +    public String getId() {
    +        return metadata.getId();
    +    }
    +
    +    @Override
    +    public String getDisplayType() {
    +        return metadata.getName();
    +    }
    +
    +    @Override
    +    public String getHelpText() {
    +        return metadata.getDescription();
    +    }
    +
    +    @Override
    +    protected String getScriptCode(ProtocolMapperModel mapperModel) {
    +        return metadata.getCode();
    +    }
    +
    +    public List<ProviderConfigProperty> getConfigProperties() {
    +        return super.getConfigProperties().stream()
    +                .filter(providerConfigProperty -> !ProviderConfigProperty.SCRIPT_TYPE.equals(providerConfigProperty.getName())) // filter "script" property
    +                .collect(Collectors.toList());
    +    }
    +
    +    public void setMetadata(ScriptProviderMetadata metadata) {
    +        this.metadata = metadata;
    +    }
    +
    +    public ScriptProviderMetadata getMetadata() {
    +        return metadata;
    +    }
    +}
    
  • services/src/main/java/org/keycloak/protocol/saml/mappers/ScriptBasedMapper.java+14 3 modified
    @@ -1,10 +1,12 @@
     package org.keycloak.protocol.saml.mappers;
     
     import org.jboss.logging.Logger;
    +import org.keycloak.common.Profile;
     import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
     import org.keycloak.dom.saml.v2.assertion.AttributeType;
     import org.keycloak.models.*;
     import org.keycloak.protocol.ProtocolMapperConfigException;
    +import org.keycloak.provider.EnvironmentDependentProviderFactory;
     import org.keycloak.provider.ProviderConfigProperty;
     import org.keycloak.scripting.EvaluatableScriptAdapter;
     import org.keycloak.scripting.ScriptCompilationException;
    @@ -20,7 +22,7 @@
      *
      * @author Alistair Doswald
      */
    -public class ScriptBasedMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper {
    +public class ScriptBasedMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper, EnvironmentDependentProviderFactory {
     
         private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
         public static final String PROVIDER_ID = "saml-javascript-mapper";
    @@ -92,6 +94,11 @@ public String getHelpText() {
             return "Evaluates a JavaScript function to produce an attribute value based on context information.";
         }
     
    +    @Override
    +    public boolean isSupported() {
    +        return Profile.isFeatureEnabled(Profile.Feature.SCRIPTS);
    +    }
    +
         /**
          *  This method attaches one or many attributes to the passed attribute statement.
          *  To obtain the attribute values, it executes the mapper's script and returns attaches the returned value to the
    @@ -110,7 +117,7 @@ public void transformAttributeStatement(AttributeStatementType attributeStatemen
                                                 KeycloakSession session, UserSessionModel userSession,
                                                 AuthenticatedClientSessionModel clientSession) {
             UserModel user = userSession.getUser();
    -        String scriptSource = mappingModel.getConfig().get(ProviderConfigProperty.SCRIPT_TYPE);
    +        String scriptSource = getScriptCode(mappingModel);
             RealmModel realm = userSession.getRealm();
     
             String single = mappingModel.getConfig().get(SINGLE_VALUE_ATTRIBUTE);
    @@ -158,7 +165,7 @@ public void transformAttributeStatement(AttributeStatementType attributeStatemen
         @Override
         public void validateConfig(KeycloakSession session, RealmModel realm, ProtocolMapperContainerModel client, ProtocolMapperModel mapperModel) throws ProtocolMapperConfigException {
     
    -        String scriptCode = mapperModel.getConfig().get(ProviderConfigProperty.SCRIPT_TYPE);
    +        String scriptCode = getScriptCode(mapperModel);
             if (scriptCode == null) {
                 return;
             }
    @@ -173,6 +180,10 @@ public void validateConfig(KeycloakSession session, RealmModel realm, ProtocolMa
             }
         }
     
    +    protected String getScriptCode(ProtocolMapperModel mappingModel) {
    +        return mappingModel.getConfig().get(ProviderConfigProperty.SCRIPT_TYPE);
    +    }
    +
         /**
          * Creates an protocol mapper model for the this script based mapper. This mapper model is meant to be used for
          * testing, as normally such objects are created in a different manner through the keycloak GUI.
    
  • services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper+0 1 modified
    @@ -36,7 +36,6 @@ org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper
     org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper
     org.keycloak.protocol.saml.mappers.UserSessionNoteStatementMapper
     org.keycloak.protocol.saml.mappers.GroupMembershipMapper
    -org.keycloak.protocol.saml.mappers.ScriptBasedMapper
     org.keycloak.protocol.oidc.mappers.UserClientRoleMappingMapper
     org.keycloak.protocol.oidc.mappers.UserRealmRoleMappingMapper
     org.keycloak.protocol.oidc.mappers.SHA256PairwiseSubMapper
    
  • testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/TestCleanup.java+1 1 modified
    @@ -52,7 +52,7 @@ public class TestCleanup {
         private final String realmName;
         private final ConcurrentLinkedDeque<Runnable> genericCleanups = new ConcurrentLinkedDeque<>();
     
    -    // Key is kind of entity (eg. "client", "role", "user" etc), Values are all kind of entities of given type to cleanup
    +    // Key is kind of entity (eg. "client", "role", "user" etc), Values are all IDs of entities of given type to cleanup
         private final ConcurrentMultivaluedHashMap<String, String> entities = new ConcurrentMultivaluedHashMap<>();
     
     
    
  • testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/script/DeployedSAMLScriptMapperTest.java+165 0 added
    @@ -0,0 +1,165 @@
    +package org.keycloak.testsuite.script;
    +
    +import java.io.IOException;
    +import java.util.Collections;
    +import java.util.stream.Stream;
    +
    +import javax.ws.rs.core.Response;
    +
    +import org.jboss.arquillian.container.test.api.Deployer;
    +import org.jboss.arquillian.container.test.api.Deployment;
    +import org.jboss.arquillian.container.test.api.TargetsContainer;
    +import org.jboss.arquillian.test.api.ArquillianResource;
    +import org.jboss.shrinkwrap.api.ShrinkWrap;
    +import org.jboss.shrinkwrap.api.asset.StringAsset;
    +import org.jboss.shrinkwrap.api.spec.JavaArchive;
    +import org.junit.After;
    +import org.junit.Assert;
    +import org.junit.Before;
    +import org.junit.BeforeClass;
    +import org.junit.Test;
    +import org.keycloak.common.Profile;
    +import org.keycloak.dom.saml.v2.assertion.AssertionType;
    +import org.keycloak.dom.saml.v2.assertion.AttributeType;
    +import org.keycloak.protocol.saml.SamlProtocol;
    +import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
    +import org.keycloak.protocol.saml.mappers.ScriptBasedMapper;
    +import org.keycloak.provider.ProviderConfigProperty;
    +import org.keycloak.representations.idm.ProtocolMapperRepresentation;
    +import org.keycloak.representations.provider.ScriptProviderDescriptor;
    +import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
    +import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
    +import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
    +import org.keycloak.testsuite.arquillian.annotation.EnableFeatures;
    +import org.keycloak.testsuite.saml.AbstractSamlTest;
    +import org.keycloak.testsuite.saml.RoleMapperTest;
    +import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
    +import org.keycloak.testsuite.updaters.ProtocolMappersUpdater;
    +import org.keycloak.testsuite.util.ContainerAssume;
    +import org.keycloak.testsuite.util.Matchers;
    +import org.keycloak.testsuite.util.SamlClient;
    +import org.keycloak.testsuite.util.SamlClientBuilder;
    +import org.keycloak.util.JsonSerialization;
    +
    +import static org.junit.Assert.assertFalse;
    +import static org.junit.Assert.assertThat;
    +import static org.keycloak.common.Profile.Feature.SCRIPTS;
    +import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
    +import static org.keycloak.testsuite.saml.RoleMapperTest.createSamlProtocolMapper;
    +import static org.keycloak.testsuite.util.SamlStreams.assertionsUnencrypted;
    +import static org.keycloak.testsuite.util.SamlStreams.attributeStatements;
    +import static org.keycloak.testsuite.util.SamlStreams.attributesUnecrypted;
    +
    +/**
    + * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
    + */
    +public class DeployedSAMLScriptMapperTest extends AbstractSamlTest {
    +
    +    private static final String SCRIPT_DEPLOYMENT_NAME = "scripts.jar";
    +
    +    private ClientAttributeUpdater cau;
    +    private ProtocolMappersUpdater pmu;
    +
    +    @Deployment(name = SCRIPT_DEPLOYMENT_NAME, managed = false, testable = false)
    +    @TargetsContainer(AUTH_SERVER_CURRENT)
    +    public static JavaArchive deploy() throws IOException {
    +        ScriptProviderDescriptor representation = new ScriptProviderDescriptor();
    +
    +        representation.addSAMLMapper("My Mapper", "mapper-a.js");
    +
    +        return ShrinkWrap.create(JavaArchive.class, SCRIPT_DEPLOYMENT_NAME)
    +                .addAsManifestResource(new StringAsset(JsonSerialization.writeValueAsPrettyString(representation)),
    +                        "keycloak-scripts.json")
    +                .addAsResource("scripts/mapper-example.js", "mapper-a.js");
    +    }
    +
    +    @BeforeClass
    +    public static void verifyEnvironment() {
    +        ContainerAssume.assumeNotAuthServerUndertow();
    +    }
    +
    +    @ArquillianResource
    +    private Deployer deployer;
    +
    +    @Before
    +    public void deployScripts() throws Exception {
    +        deployer.deploy(SCRIPT_DEPLOYMENT_NAME);
    +        reconnectAdminClient();
    +    }
    +
    +    @Before
    +    public void cleanMappersAndScopes() {
    +        this.cau = ClientAttributeUpdater.forClient(adminClient, REALM_NAME, SAML_CLIENT_ID_EMPLOYEE_2)
    +                .setDefaultClientScopes(Collections.EMPTY_LIST)
    +                .update();
    +        this.pmu = cau.protocolMappers()
    +                .clear()
    +                .update();
    +
    +        getCleanup(REALM_NAME)
    +                .addCleanup(this.cau)
    +                .addCleanup(this.pmu);
    +    }
    +
    +    @After
    +    public void onAfter() throws Exception {
    +        deployer.undeploy(SCRIPT_DEPLOYMENT_NAME);
    +        reconnectAdminClient();
    +    }
    +
    +    @Test
    +    public void testScriptMapperNotAvailableThroughAdminRest() {
    +        assertFalse(adminClient.serverInfo().getInfo().getProtocolMapperTypes().get(SamlProtocol.LOGIN_PROTOCOL).stream()
    +                .anyMatch(
    +                        mapper -> ScriptBasedMapper.PROVIDER_ID.equals(mapper.getId())));
    +
    +        // Doublecheck not possible to create mapper through admin REST
    +        ProtocolMapperRepresentation mapperRep = createSamlProtocolMapper(ScriptBasedMapper.PROVIDER_ID,
    +                ProviderConfigProperty.SCRIPT_TYPE, "'hello_' + user.username",
    +                AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, AttributeStatementHelper.BASIC,
    +                AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "SCRIPT_ATTRIBUTE"
    +        );
    +
    +        Response response = pmu.getResource().createMapper(mapperRep);
    +        Assert.assertEquals(404, response.getStatus());
    +        response.close();
    +    }
    +
    +
    +    @Test
    +    @EnableFeature(value = SCRIPTS, skipRestart = true, executeAsLast = false)
    +    public void testScriptMappingThroughServerDeploy() {
    +        // ScriptBasedMapper still not available even if SCRIPTS feature is enabled
    +        testScriptMapperNotAvailableThroughAdminRest();
    +
    +        pmu.add(
    +                createSamlProtocolMapper("script-mapper-a.js",
    +                        AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, AttributeStatementHelper.BASIC,
    +                        AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "SCRIPT_ATTRIBUTE"
    +                )
    +        ).update();
    +
    +        assertLoginSuccessWithAttributeAvailable();
    +    }
    +
    +
    +    private void assertLoginSuccessWithAttributeAvailable() {
    +        SAMLDocumentHolder samlResponse = new SamlClientBuilder()
    +                .authnRequest(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_EMPLOYEE_2, RoleMapperTest.SAML_ASSERTION_CONSUMER_URL_EMPLOYEE_2, SamlClient.Binding.POST)
    +                .build()
    +                .login().user(bburkeUser).build()
    +                .getSamlResponse(SamlClient.Binding.POST);
    +
    +        assertThat(samlResponse.getSamlObject(), Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
    +
    +        Stream<AssertionType> assertions = assertionsUnencrypted(samlResponse.getSamlObject());
    +        Stream<AttributeType> attributes = attributesUnecrypted(attributeStatements(assertions));
    +        String scriptAttrValue = attributes
    +                .filter(attribute -> "SCRIPT_ATTRIBUTE".equals(attribute.getName()))
    +                .map(attribute -> attribute.getAttributeValue().get(0).toString())
    +                .findFirst().orElseThrow(() -> new AssertionError("Attribute SCRIPT_ATTRIBUTE was not available in SAML assertion"));
    +
    +        Assert.assertEquals("hello_bburke", scriptAttrValue);
    +    }
    +
    +}
    
  • testsuite/utils/src/main/java/org/keycloak/testsuite/KeycloakServer.java+4 0 modified
    @@ -40,6 +40,7 @@
     import org.keycloak.platform.Platform;
     import org.keycloak.protocol.ProtocolMapperSpi;
     import org.keycloak.protocol.oidc.mappers.DeployedScriptOIDCProtocolMapper;
    +import org.keycloak.protocol.saml.mappers.DeployedScriptSAMLProtocolMapper;
     import org.keycloak.provider.KeycloakDeploymentInfo;
     import org.keycloak.provider.ProviderFactory;
     import org.keycloak.provider.ProviderManager;
    @@ -601,6 +602,9 @@ public static void registerScriptProviders(DefaultKeycloakSessionFactory session
                 addScriptProvider(info, scriptProviderDescriptor.getProviders().getOrDefault("mappers", Collections.emptyList()),
                         ProtocolMapperSpi.class,
                         DeployedScriptOIDCProtocolMapper::new);
    +            addScriptProvider(info, scriptProviderDescriptor.getProviders().getOrDefault("saml-mappers", Collections.emptyList()),
    +                    ProtocolMapperSpi.class,
    +                    DeployedScriptSAMLProtocolMapper::new);
                 addScriptProvider(info, scriptProviderDescriptor.getProviders().getOrDefault("policies", Collections.emptyList()),
                         PolicySpi.class,
                         DeployedScriptPolicyFactory::new);
    
  • wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/ScriptProviderDeploymentProcessor.java+7 0 modified
    @@ -19,6 +19,7 @@
     import static org.keycloak.representations.provider.ScriptProviderDescriptor.AUTHENTICATORS;
     import static org.keycloak.representations.provider.ScriptProviderDescriptor.MAPPERS;
     import static org.keycloak.representations.provider.ScriptProviderDescriptor.POLICIES;
    +import static org.keycloak.representations.provider.ScriptProviderDescriptor.SAML_MAPPERS;
     
     import java.io.IOException;
     import java.io.InputStream;
    @@ -39,6 +40,7 @@
     import org.keycloak.common.util.StreamUtil;
     import org.keycloak.protocol.ProtocolMapperSpi;
     import org.keycloak.protocol.oidc.mappers.DeployedScriptOIDCProtocolMapper;
    +import org.keycloak.protocol.saml.mappers.DeployedScriptSAMLProtocolMapper;
     import org.keycloak.provider.KeycloakDeploymentInfo;
     import org.keycloak.representations.provider.ScriptProviderDescriptor;
     import org.keycloak.representations.provider.ScriptProviderMetadata;
    @@ -63,6 +65,10 @@ private static void registerScriptMapper(KeycloakDeploymentInfo info, ScriptProv
             info.addProvider(ProtocolMapperSpi.class, new DeployedScriptOIDCProtocolMapper(metadata));
         }
     
    +    private static void registerSAMLScriptMapper(KeycloakDeploymentInfo info, ScriptProviderMetadata metadata) {
    +        info.addProvider(ProtocolMapperSpi.class, new DeployedScriptSAMLProtocolMapper(metadata));
    +    }
    +
         static void deploy(DeploymentUnit deploymentUnit, KeycloakDeploymentInfo info) {
             ResourceRoot resourceRoot = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);
     
    @@ -129,5 +135,6 @@ private static ScriptProviderDescriptor readScriptProviderDescriptor(VirtualFile
             PROVIDERS.put(AUTHENTICATORS, ScriptProviderDeploymentProcessor::registerScriptAuthenticator);
             PROVIDERS.put(POLICIES, ScriptProviderDeploymentProcessor::registerScriptPolicy);
             PROVIDERS.put(MAPPERS, ScriptProviderDeploymentProcessor::registerScriptMapper);
    +        PROVIDERS.put(SAML_MAPPERS, ScriptProviderDeploymentProcessor::registerSAMLScriptMapper);
         }
     }
    

Vulnerability mechanics

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

References

6

News mentions

0

No linked articles in our index yet.