VYPR
Critical severityNVD Advisory· Published Oct 26, 2022· Updated May 7, 2025

Apache Flume prior to 1.11.0 has an Improper Input Validation (JNDI Injection) in JMSSource

CVE-2022-42468

Description

Apache Flume 1.4.0 to 1.10.1 allows remote code execution via JMS Source due to unsafe JNDI providerURL, fixed by restricting JNDI protocols to 'java'.

AI Insight

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

Apache Flume 1.4.0 to 1.10.1 allows remote code execution via JMS Source due to unsafe JNDI providerURL, fixed by restricting JNDI protocols to 'java'.

Vulnerability

Overview

CVE-2022-42468 is a remote code execution vulnerability in Apache Flume, affecting versions 1.4.0 through 1.10.1. The flaw resides in the JMS Source component, which lacks proper validation of the JNDI provider URL (providerURL). When an attacker can control this configuration parameter, they can supply a malicious JNDI URI referencing an attacker-controlled LDAP or RMI server, leading to arbitrary code execution via JNDI injection [1][2][3].

Exploitation

Mechanism

The vulnerability is triggered when a Flume agent is configured to use a JMS Source with an unsafe providerURL. An attacker with the ability to modify this configuration—for instance, by compromising the configuration store or tricking an administrator into applying a malicious configuration—can specify a JNDI URI that uses protocols such as LDAP or RMI. On lookup, the JNDI client fetches a remote object, which can execute arbitrary Java code on the Flume agent [1][3]. No authentication is required beyond the ability to set the configuration value.

Impact

Successful exploitation grants an attacker full remote code execution on the machine running the affected Apache Flume instance. This could allow the attacker to compromise the log data pipeline, access sensitive data, pivot to other systems, or use the compromised host as a foothold for further attacks [2][3].

Mitigation

Apache Flume 1.11.0 and later include a fix that adds a new JVM system property, JndiAllowedProtocols, which by default restricts JNDI lookups to only the java protocol. The fix validates the scheme of the JNDI URI against this whitelist [1][3]. Users unable to upgrade immediately should ensure that the providerURL in JMS Source configurations is never set from untrusted input and apply appropriate network controls. The issue was resolved in October 2022 via commit eee179a [1].

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.

PackageAffected versionsPatched versions
org.apache.flume.flume-ng-sources:flume-jms-sourceMaven
< 1.11.01.11.0

Affected products

2

Patches

1
eee179a09df4

FLUME-3437 - Improve JMSSource validation

https://github.com/apache/flumeRalph GoersSep 23, 2022via ghsa
5 files changed · +46 46
  • flume-ng-sources/flume-jms-source/src/main/java/org/apache/flume/source/jms/JMSMessageConsumer.java+1 15 modified
    @@ -35,14 +35,11 @@
     import javax.jms.Topic;
     import javax.naming.InitialContext;
     import javax.naming.NamingException;
    -import java.net.URI;
    -import java.net.URISyntaxException;
     import java.util.ArrayList;
     import java.util.List;
     
     class JMSMessageConsumer {
       private static final Logger logger = LoggerFactory.getLogger(JMSMessageConsumer.class);
    -  private static final String JAVA_SCHEME = "java";
     
       private final int batchSize;
       private final long pollTimeout;
    @@ -102,14 +99,7 @@ class JMSMessageConsumer {
                   throw new IllegalStateException(String.valueOf(destinationType));
               }
             } else {
    -          try {
    -            URI uri = new URI(destinationName);
    -            String scheme = uri.getScheme();
    -            assertTrue(scheme == null || scheme.equals(JAVA_SCHEME),
    -                "Unsupported JNDI URI: " + destinationName);
    -          } catch (URISyntaxException ex) {
    -            logger.warn("Invalid JNDI URI - {}", destinationName);
    -          }
    +          JMSSource.verifyContext(destinationName);
               destination = (Destination) initialContext.lookup(destinationName);
             }
           } catch (JMSException e) {
    @@ -220,8 +210,4 @@ void close() {
           logger.error("Could not destroy connection", e);
         }
       }
    -
    -  private void assertTrue(boolean arg, String msg) {
    -    Preconditions.checkArgument(arg, msg);
    -  }
     }
    
  • flume-ng-sources/flume-jms-source/src/main/java/org/apache/flume/source/jms/JMSMessageConverter.java+3 3 modified
    @@ -39,13 +39,13 @@
     @InterfaceStability.Stable
     public interface JMSMessageConverter {
     
    -  public List<Event> convert(Message message) throws JMSException;
    +  List<Event> convert(Message message) throws JMSException;
     
       /**
        * Implementors of JMSMessageConverter must either provide
        * a suitable builder or implement the Configurable interface.
        */
    -  public interface Builder {
    -    public JMSMessageConverter build(Context context);
    +  interface Builder {
    +    JMSMessageConverter build(Context context);
       }
     }
    
  • flume-ng-sources/flume-jms-source/src/main/java/org/apache/flume/source/jms/JMSSource.java+40 28 modified
    @@ -21,6 +21,8 @@
     import java.io.IOException;
     import java.net.URI;
     import java.net.URISyntaxException;
    +import java.util.ArrayList;
    +import java.util.Collections;
     import java.util.List;
     import java.util.Locale;
     import java.util.Properties;
    @@ -56,6 +58,7 @@
     public class JMSSource extends AbstractPollableSource implements BatchSizeSupported {
       private static final Logger logger = LoggerFactory.getLogger(JMSSource.class);
       private static final String JAVA_SCHEME = "java";
    +  public static final String JNDI_ALLOWED_PROTOCOLS = "JndiAllowedProtocols";
     
       // setup by constructor
       private final InitialContextFactory initialContextFactory;
    @@ -82,6 +85,7 @@ public class JMSSource extends AbstractPollableSource implements BatchSizeSuppor
     
       private int jmsExceptionCounter;
       private InitialContext initialContext;
    +  private static List<String> allowedSchemes = getAllowedProtocols();
     
       public JMSSource() {
         this(new InitialContextFactory());
    @@ -92,6 +96,34 @@ public JMSSource(InitialContextFactory initialContextFactory) {
         this.initialContextFactory = initialContextFactory;
       }
     
    +  private static List<String> getAllowedProtocols() {
    +    String allowed = System.getProperty(JNDI_ALLOWED_PROTOCOLS, null);
    +    if (allowed == null) {
    +      return Collections.singletonList(JAVA_SCHEME);
    +    } else {
    +      String[] items = allowed.split(",");
    +      List<String> schemes = new ArrayList<>();
    +      schemes.add(JAVA_SCHEME);
    +      for (String item : items) {
    +        if (!item.equals(JAVA_SCHEME)) {
    +          schemes.add(item.trim());
    +        }
    +      }
    +      return schemes;
    +    }
    +  }
    +
    +  public static void verifyContext(String location) {
    +    try {
    +      String scheme = new URI(location).getScheme();
    +      if (scheme != null && !allowedSchemes.contains(scheme)) {
    +        throw new IllegalArgumentException("Invalid JNDI URI: " + location);
    +      }
    +    } catch (URISyntaxException ex) {
    +      logger.trace("{}} is not a valid URI", location);
    +    }
    +  }
    +
       @Override
       protected void doConfigure(Context context) throws FlumeException {
         sourceCounter = new SourceCounter(getName());
    @@ -100,14 +132,7 @@ protected void doConfigure(Context context) throws FlumeException {
             JMSSourceConfiguration.INITIAL_CONTEXT_FACTORY, "").trim();
     
         providerUrl = context.getString(JMSSourceConfiguration.PROVIDER_URL, "").trim();
    -    try {
    -      URI uri = new URI(providerUrl);
    -      String scheme = uri.getScheme();
    -      assertTrue(scheme == null || scheme.equals(JAVA_SCHEME),
    -          "Unsupported JNDI URI: " + providerUrl);
    -    } catch (URISyntaxException ex) {
    -      logger.warn("Invalid JNDI URI - {}", providerUrl);
    -    }
    +    verifyContext(providerUrl);
     
         destinationName = context.getString(JMSSourceConfiguration.DESTINATION_NAME, "").trim();
     
    @@ -190,14 +215,7 @@ protected void doConfigure(Context context) throws FlumeException {
         String connectionFactoryName = context.getString(
             JMSSourceConfiguration.CONNECTION_FACTORY,
             JMSSourceConfiguration.CONNECTION_FACTORY_DEFAULT).trim();
    -    try {
    -      URI uri = new URI(connectionFactoryName);
    -      String scheme = uri.getScheme();
    -      assertTrue(scheme == null || scheme.equals(JAVA_SCHEME),
    -          "Unsupported JNDI URI: " + connectionFactoryName);
    -    } catch (URISyntaxException ex) {
    -      logger.warn("Invalid JNDI URI - {}", connectionFactoryName);
    -    }
    +    verifyContext(connectionFactoryName);
     
         assertNotEmpty(initialContextFactoryName, String.format(
             "Initial Context Factory is empty. This is specified by %s",
    @@ -291,10 +309,6 @@ private void assertNotEmpty(String arg, String msg) {
         Preconditions.checkArgument(!arg.isEmpty(), msg);
       }
     
    -  private void assertTrue(boolean arg, String msg) {
    -    Preconditions.checkArgument(arg, msg);
    -  }
    -
       @Override
       protected synchronized Status doProcess() throws EventDeliveryException {
         boolean error = true;
    @@ -322,14 +336,12 @@ protected synchronized Status doProcess() throws EventDeliveryException {
           sourceCounter.incrementChannelWriteFail();
         } catch (JMSException jmsException) {
           logger.warn("JMSException consuming events", jmsException);
    -      if (++jmsExceptionCounter > errorThreshold) {
    -        if (consumer != null) {
    -          logger.warn("Exceeded JMSException threshold, closing consumer");
    -          sourceCounter.incrementEventReadFail();
    -          consumer.rollback();
    -          consumer.close();
    -          consumer = null;
    -        }
    +      if (++jmsExceptionCounter > errorThreshold && consumer != null) {
    +        logger.warn("Exceeded JMSException threshold, closing consumer");
    +        sourceCounter.incrementEventReadFail();
    +        consumer.rollback();
    +        consumer.close();
    +        consumer = null;
           }
         } catch (Throwable throwable) {
           logger.error("Unexpected error processing events", throwable);
    
  • flume-ng-sources/flume-jms-source/src/test/java/org/apache/flume/source/jms/TestIntegrationActiveMQ.java+1 0 modified
    @@ -90,6 +90,7 @@ private enum TestMode {
       private final String jmsPassword;
     
       public TestIntegrationActiveMQ(TestMode testMode) {
    +    System.setProperty(JMSSource.JNDI_ALLOWED_PROTOCOLS, "tcp");
         LOGGER.info("Testing with test mode {}", testMode);
     
         switch (testMode) {
    
  • flume-ng-sources/flume-jms-source/src/test/java/org/apache/flume/source/jms/TestJMSSource.java+1 0 modified
    @@ -64,6 +64,7 @@ public class TestJMSSource extends JMSMessageConsumerTestBase {
       @SuppressWarnings("unchecked")
       @Override
       void afterSetup() throws Exception {
    +    System.setProperty(JMSSource.JNDI_ALLOWED_PROTOCOLS, "dummy");
         baseDir = Files.createTempDir();
         passwordFile = new File(baseDir, "password");
         Assert.assertTrue(passwordFile.createNewFile());
    

Vulnerability mechanics

Generated 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.