VYPR
Moderate severityNVD Advisory· Published Jun 12, 2023· Updated Feb 13, 2025

Apache NiFi: Potential Deserialization of Untrusted Data with JNDI in JMS Components

CVE-2023-34212

Description

The JndiJmsConnectionFactoryProvider Controller Service, along with the ConsumeJMS and PublishJMS Processors, in Apache NiFi 1.8.0 through 1.21.0 allow an authenticated and authorized user to configure URL and library properties that enable deserialization of untrusted data from a remote location.

The resolution validates the JNDI URL and restricts locations to a set of allowed schemes.

You are recommended to upgrade to version 1.22.0 or later which fixes this issue.

AI Insight

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

Authenticated users in Apache NiFi 1.8.0-1.21.0 can exploit JNDI JMS components to deserialize untrusted data from remote locations, fixed in 1.22.0 by URL validation.

The vulnerability resides in the JndiJmsConnectionFactoryProvider Controller Service and the ConsumeJMS and PublishJMS Processors in Apache NiFi versions 1.8.0 through 1.21.0. These components allow an authenticated and authorized user to configure JNDI URL and library properties, which can lead to deserialization of untrusted data from a remote location [1][2].

Exploitation requires a user with appropriate authentication and authorization within NiFi. The attacker can set a malicious JNDI URL that points to a remote server hosting a crafted serialized object. When the processor or controller service uses this configuration, the remote data is deserialized, potentially allowing arbitrary code execution [2].

The impact is significant because deserialization of untrusted data can lead to remote code execution, enabling an attacker to compromise the NiFi instance and the data it processes [2].

Apache NiFi has addressed this issue in version 1.22.0 by validating the JNDI URL and restricting locations to a set of allowed schemes, such as only LDAP over TCP [4]. Users are strongly recommended to upgrade to 1.22.0 or later to mitigate this vulnerability [1].

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.apache.nifi:nifi-jms-processorsMaven
>= 1.8.0, < 1.22.01.22.0

Affected products

3

Patches

1
3fcb82ee4509

NIFI-11614 Improved Validation for JndiJmsConnectionFactoryProvider

https://github.com/apache/nifiexceptionfactoryMay 30, 2023via ghsa
3 files changed · +255 5
  • nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JndiJmsConnectionFactoryProperties.java+88 2 modified
    @@ -18,19 +18,29 @@
     
     import org.apache.nifi.components.PropertyDescriptor;
     import org.apache.nifi.components.PropertyDescriptor.Builder;
    +import org.apache.nifi.components.ValidationContext;
    +import org.apache.nifi.components.ValidationResult;
     import org.apache.nifi.components.Validator;
     import org.apache.nifi.components.resource.ResourceCardinality;
     import org.apache.nifi.components.resource.ResourceType;
     import org.apache.nifi.expression.ExpressionLanguageScope;
     import org.apache.nifi.processor.util.StandardValidators;
     
     import java.util.Arrays;
    +import java.util.Collections;
    +import java.util.LinkedHashSet;
     import java.util.List;
    +import java.util.Set;
    +import java.util.regex.Matcher;
    +import java.util.regex.Pattern;
    +import java.util.stream.Collectors;
     
     import static org.apache.nifi.processor.util.StandardValidators.NON_EMPTY_VALIDATOR;
     
     public class JndiJmsConnectionFactoryProperties {
     
    +    public static final String URL_SCHEMES_ALLOWED_PROPERTY = "org.apache.nifi.jms.cf.jndi.provider.url.schemes.allowed";
    +
         public static final PropertyDescriptor JNDI_INITIAL_CONTEXT_FACTORY = new Builder()
                 .name("java.naming.factory.initial")
                 .displayName("JNDI Initial Context Factory Class")
    @@ -43,9 +53,9 @@ public class JndiJmsConnectionFactoryProperties {
         public static final PropertyDescriptor JNDI_PROVIDER_URL = new Builder()
                 .name("java.naming.provider.url")
                 .displayName("JNDI Provider URL")
    -            .description("The URL of the JNDI Provider to use (java.naming.provider.url).")
    +            .description("The URL of the JNDI Provider to use as the value for java.naming.provider.url. See additional details documentation for allowed URL schemes.")
                 .required(true)
    -            .addValidator(NON_EMPTY_VALIDATOR)
    +            .addValidator(new JndiJmsProviderUrlValidator())
                 .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
                 .build();
     
    @@ -114,4 +124,80 @@ public static PropertyDescriptor getDynamicPropertyDescriptor(final String prope
                     .build();
         }
     
    +    static class JndiJmsProviderUrlValidator implements Validator {
    +
    +        private static final Pattern URL_SCHEME_PATTERN = Pattern.compile("^([^:]+)://.+$");
    +
    +        private static final int SCHEME_GROUP = 1;
    +
    +        private static final String SPACE_SEPARATOR = " ";
    +
    +        private static final Set<String> DEFAULT_ALLOWED_SCHEMES = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(
    +                "file",
    +                "jgroups",
    +                "t3",
    +                "t3s",
    +                "tcp",
    +                "ssl",
    +                "udp",
    +                "vm"
    +        )));
    +
    +        private final Set<String> allowedSchemes;
    +
    +        JndiJmsProviderUrlValidator() {
    +            final String allowed = System.getProperty(URL_SCHEMES_ALLOWED_PROPERTY);
    +            if (allowed == null || allowed.isEmpty()) {
    +                allowedSchemes = DEFAULT_ALLOWED_SCHEMES;
    +            } else {
    +                allowedSchemes = Arrays.stream(allowed.split(SPACE_SEPARATOR)).collect(Collectors.toSet());
    +            }
    +        }
    +
    +        @Override
    +        public ValidationResult validate(final String subject, final String input, final ValidationContext context) {
    +            final ValidationResult.Builder builder = new ValidationResult.Builder().subject(subject).input(input);
    +
    +            if (input == null || input.isEmpty()) {
    +                builder.valid(false);
    +                builder.explanation("URL is required");
    +            } else if (isUrlAllowed(input)) {
    +                builder.valid(true);
    +                builder.explanation("URL scheme allowed");
    +            } else {
    +                builder.valid(false);
    +                final String explanation = String.format("URL scheme not allowed. Allowed URL schemes include %s", allowedSchemes);
    +                builder.explanation(explanation);
    +            }
    +
    +            return builder.build();
    +        }
    +
    +        private boolean isUrlAllowed(final String input) {
    +            final boolean allowed;
    +
    +            final Matcher matcher = URL_SCHEME_PATTERN.matcher(input);
    +            if (matcher.matches()) {
    +                final String scheme = matcher.group(SCHEME_GROUP);
    +                allowed = isSchemeAllowed(scheme);
    +            } else {
    +                allowed = true;
    +            }
    +
    +            return allowed;
    +        }
    +
    +        private boolean isSchemeAllowed(final String scheme) {
    +            boolean allowed = false;
    +
    +            for (final String allowedScheme : allowedSchemes) {
    +                if (allowedScheme.contains(scheme)) {
    +                    allowed = true;
    +                    break;
    +                }
    +            }
    +
    +            return allowed;
    +        }
    +    }
     }
    
  • nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/resources/docs/org.apache.nifi.jms.cf.JndiJmsConnectionFactoryProvider/additionalDetails.html+51 3 modified
    @@ -21,9 +21,9 @@
     </head>
     
     <body>
    -<h2>Description:</h2>
    +<h2>Capabilities</h2>
     <p>
    -    This ControllerService allows users to reference a JMS Connection Factory that has already been established and
    +    This Controller Service allows users to reference a JMS Connection Factory that has already been established and
         made available via Java Naming and Directory Interface (JNDI) Server. Please see documentation from your JMS Vendor in order
         to understand the appropriate values to configure for this service.
     </p>
    @@ -55,7 +55,7 @@ <h2>Description:</h2>
     </p>
     
     
    -<h2>Example:</h2>
    +<h2>Example Configuration</h2>
     
     <p>
         As an example, the following configuration may be used to connect to Active MQ's JMS Broker, using the Connection Factory provided via their embedded JNDI server:
    @@ -91,5 +91,53 @@ <h2>Example:</h2>
         the jar(s) containing the org.apache.activemq.jndi.ActiveMQInitialContextFactory class and the other JMS client classes can be found within the /opt/apache-activemq-5.15.2/lib/ directory.
     </p>
     
    +<h2>Property Validation</h2>
    +
    +<p>
    +  The following component properties include additional validation to restrict allowed values:
    +</p>
    +
    +<ul>
    +  <li>JNDI Provider URL</li>
    +</ul>
    +
    +<h3>JNDI Provider URL Validation</h3>
    +
    +<p>
    +  The default validation for <code>JNDI Provider URL</code> allows the following URL schemes:
    +</p>
    +
    +<ul>
    +  <li>file</li>
    +  <li>jgroups</li>
    +  <li>ssl</li>
    +  <li>t3</li>
    +  <li>t3s</li>
    +  <li>tcp</li>
    +  <li>udp</li>
    +  <li>vm</li>
    +</ul>
    +
    +<p>
    +  The following Java System property can be configured to override the default allowed URL schemes:
    +</p>
    +
    +<ul>
    +  <li>
    +    <code>org.apache.nifi.jms.cf.jndi.provider.url.schemes.allowed</code>
    +  </li>
    +</ul>
    +
    +<p>
    +  The System property must contain a space-separated list of URL schemes. This property can be configured in the application
    +  <code>bootstrap.conf</code> as follows:
    +</p>
    +
    +<ul>
    +  <li>
    +    <code>java.arg.jndiJmsUrlSchemesAllowed=-Dorg.apache.nifi.jms.cf.jndi.provider.url.schemes.allowed=ssl tcp</code>
    +  </li>
    +</ul>
    +
     </body>
     </html>
    
  • nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/test/java/org/apache/nifi/jms/cf/JndiJmsConnectionFactoryProviderTest.java+116 0 added
    @@ -0,0 +1,116 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one or more
    + * contributor license agreements.  See the NOTICE file distributed with
    + * this work for additional information regarding copyright ownership.
    + * The ASF licenses this file to You under the Apache License, Version 2.0
    + * (the "License"); you may not use this file except in compliance with
    + * the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package org.apache.nifi.jms.cf;
    +
    +import org.apache.nifi.components.ValidationResult;
    +import org.apache.nifi.reporting.InitializationException;
    +import org.apache.nifi.util.MockProcessContext;
    +import org.apache.nifi.util.MockValidationContext;
    +import org.apache.nifi.util.NoOpProcessor;
    +import org.apache.nifi.util.TestRunner;
    +import org.apache.nifi.util.TestRunners;
    +import org.junit.jupiter.api.BeforeEach;
    +import org.junit.jupiter.api.Test;
    +
    +import static org.junit.jupiter.api.Assertions.assertNotNull;
    +import static org.junit.jupiter.api.Assertions.assertTrue;
    +
    +public class JndiJmsConnectionFactoryProviderTest {
    +
    +    private static final String SERVICE_ID = JndiJmsConnectionFactoryProvider.class.getSimpleName();
    +
    +    private static final String CONTEXT_FACTORY = "ContextFactory";
    +
    +    private static final String FACTORY_NAME = "ConnectionFactory";
    +
    +    private static final String TCP_PROVIDER_URL = "tcp://127.0.0.1";
    +
    +    private static final String LDAP_PROVIDER_URL = "ldap://127.0.0.1";
    +
    +    private static final String HOST_PORT_URL = "127.0.0.1:1024";
    +
    +    private static final String LDAP_ALLOWED_URL_SCHEMES = "ldap";
    +
    +    private TestRunner runner;
    +
    +    private JndiJmsConnectionFactoryProvider provider;
    +
    +    @BeforeEach
    +    void setRunner() throws InitializationException {
    +        runner = TestRunners.newTestRunner(NoOpProcessor.class);
    +        provider = new JndiJmsConnectionFactoryProvider();
    +        runner.addControllerService(SERVICE_ID, provider);
    +    }
    +
    +    @Test
    +    void testPropertiesValid() {
    +        setFactoryProperties();
    +
    +        runner.setProperty(provider, JndiJmsConnectionFactoryProperties.JNDI_PROVIDER_URL, TCP_PROVIDER_URL);
    +
    +        runner.assertValid(provider);
    +    }
    +
    +    @Test
    +    void testPropertiesInvalidUrlNotConfigured() {
    +        setFactoryProperties();
    +
    +        runner.assertNotValid(provider);
    +    }
    +
    +    @Test
    +    void testPropertiesInvalidUrlScheme() {
    +        setFactoryProperties();
    +
    +        runner.setProperty(provider, JndiJmsConnectionFactoryProperties.JNDI_PROVIDER_URL, LDAP_PROVIDER_URL);
    +
    +        runner.assertNotValid(provider);
    +    }
    +
    +    @Test
    +    void testPropertiesHostPortUrl() {
    +        setFactoryProperties();
    +
    +        runner.setProperty(provider, JndiJmsConnectionFactoryProperties.JNDI_PROVIDER_URL, HOST_PORT_URL);
    +
    +        runner.assertValid(provider);
    +    }
    +
    +
    +    @Test
    +    void testUrlSchemeValidSystemProperty() {
    +        try {
    +            System.setProperty(JndiJmsConnectionFactoryProperties.URL_SCHEMES_ALLOWED_PROPERTY, LDAP_ALLOWED_URL_SCHEMES);
    +
    +            final MockProcessContext processContext = new MockProcessContext(new NoOpProcessor());
    +            final MockValidationContext validationContext = new MockValidationContext(processContext);
    +
    +            final JndiJmsConnectionFactoryProperties.JndiJmsProviderUrlValidator validator = new JndiJmsConnectionFactoryProperties.JndiJmsProviderUrlValidator();
    +            final ValidationResult result = validator.validate(JndiJmsConnectionFactoryProperties.JNDI_PROVIDER_URL.getDisplayName(), LDAP_PROVIDER_URL, validationContext);
    +
    +            assertNotNull(result);
    +            assertTrue(result.isValid());
    +        } finally {
    +            System.clearProperty(JndiJmsConnectionFactoryProperties.URL_SCHEMES_ALLOWED_PROPERTY);
    +        }
    +    }
    +
    +    private void setFactoryProperties() {
    +        runner.setProperty(provider, JndiJmsConnectionFactoryProperties.JNDI_INITIAL_CONTEXT_FACTORY, CONTEXT_FACTORY);
    +        runner.setProperty(provider, JndiJmsConnectionFactoryProperties.JNDI_CONNECTION_FACTORY_NAME, FACTORY_NAME);
    +    }
    +}
    

Vulnerability mechanics

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

References

8

News mentions

0

No linked articles in our index yet.