VYPR
High severityNVD Advisory· Published Apr 13, 2022· Updated Apr 23, 2025

Improper Input Validation in GeoServer

CVE-2022-24847

Description

GeoServer is an open source software server written in Java that allows users to share and edit geospatial data. The GeoServer security mechanism can perform an unchecked JNDI lookup, which in turn can be used to perform class deserialization and result in arbitrary code execution. The same can happen while configuring data stores with data sources located in JNDI, or while setting up the disk quota mechanism. In order to perform any of the above changes, the attack needs to have obtained admin rights and use either the GeoServer GUI, or its REST API. The lookups are going to be restricted in GeoServer 2.21.0, 2.20.4, 1.19.6. Users unable to upgrade should restrict access to the geoserver/web and geoserver/rest via a firewall and ensure that the GeoWebCache is not remotely accessible.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.geoserver:gs-mainMaven
>= 2.20.0, < 2.20.42.20.4
org.geoserver:gs-mainMaven
< 2.19.62.19.6

Affected products

1

Patches

1
b94a69943992

[GEOS-10460] Centralize JNDI lookups

https://github.com/geoserver/geoserverAndrea AimeApr 11, 2022via ghsa
5 files changed · +27 60
  • src/community/jdbcconfig/src/main/java/org/geoserver/jdbcloader/DataSourceFactoryBean.java+1 26 modified
    @@ -11,7 +11,6 @@
     import java.util.Properties;
     import java.util.logging.Level;
     import java.util.logging.Logger;
    -import javax.naming.Context;
     import javax.naming.NamingException;
     import javax.sql.DataSource;
     import org.apache.commons.dbcp.BasicDataSource;
    @@ -26,33 +25,10 @@ public class DataSourceFactoryBean implements FactoryBean<DataSource>, Disposabl
         private static final Logger LOGGER = Logging.getLogger(DataSourceFactoryBean.class);
     
         JDBCLoaderProperties config;
    -    Context jndiCtx;
         DataSource dataSource;
     
    -    private static Context getJNDI(JDBCLoaderProperties config) {
    -        if (config.isEnabled() && config.getJndiName().isPresent()) {
    -            try {
    -                return GeoTools.getInitialContext(GeoTools.getDefaultHints());
    -            } catch (NamingException ex) {
    -                LOGGER.log(
    -                        Level.WARNING,
    -                        "Could not get JNDI Context, will not use JNDI to locate DataSource",
    -                        ex);
    -                return null;
    -            }
    -        } else {
    -            // Don't bother trying to get a JNDI context if JNDI lookup isn't needed.
    -            return null;
    -        }
    -    }
    -
         public DataSourceFactoryBean(JDBCLoaderProperties config) {
    -        this(config, getJNDI(config));
    -    }
    -
    -    public DataSourceFactoryBean(JDBCLoaderProperties config, Context jndiCtx) {
             this.config = config;
    -        this.jndiCtx = jndiCtx;
         }
     
         @Override
    @@ -121,11 +97,10 @@ protected BasicDataSource createBasicDataSource() {
     
         /** Try to lookup a configured DataSource using JNDI. */
         protected Optional<DataSource> getJNDIDataSource(Optional<String> name) {
    -        if (jndiCtx == null) return Optional.absent();
     
             if (name.isPresent()) {
                 try {
    -                Optional<DataSource> ds = Optional.of((DataSource) jndiCtx.lookup(name.get()));
    +                Optional<DataSource> ds = Optional.of((DataSource) GeoTools.jndiLookup(name.get()));
                     if (LOGGER.isLoggable(Level.INFO)) {
                         LOGGER.log(Level.INFO, "JDBCLoader using JNDI DataSource {0}", name.get());
                     }
    
  • src/community/jdbcconfig/src/test/java/org/geoserver/jdbcconfig/internal/DataSourceFactoryBeanTest.java+11 9 modified
    @@ -16,12 +16,13 @@
     import com.google.common.base.Optional;
     import java.sql.Connection;
     import java.sql.DatabaseMetaData;
    -import javax.naming.Context;
    +import javax.naming.InitialContext;
     import javax.naming.NamingException;
     import javax.sql.DataSource;
     import org.apache.commons.dbcp.BasicDataSource;
     import org.easymock.EasyMock;
     import org.geoserver.jdbcloader.DataSourceFactoryBean;
    +import org.geotools.util.factory.GeoTools;
     import org.junit.Test;
     
     /** @author Kevin Smith, OpenGeo */
    @@ -31,7 +32,6 @@ public class DataSourceFactoryBeanTest {
         public void testBasic() throws Exception {
             final BasicDataSource ds = EasyMock.createMock(BasicDataSource.class);
             JDBCConfigProperties config = EasyMock.createMock(JDBCConfigProperties.class);
    -        Context jndi = EasyMock.createMock(Context.class);
     
             expect(config.isEnabled()).andReturn(true);
             expectJndi(config, null);
    @@ -73,10 +73,10 @@ public void testBasic() throws Exception {
             expectLastCall();
     
             expectVerifyConnect(ds);
    -        replay(ds, config, jndi);
    +        replay(ds, config);
     
             DataSourceFactoryBean fact =
    -                new DataSourceFactoryBean(config, jndi) {
    +                new DataSourceFactoryBean(config) {
     
                         @Override
                         protected BasicDataSource createBasicDataSource() {
    @@ -92,7 +92,7 @@ protected BasicDataSource createBasicDataSource() {
     
             // Check that the same DataSource is returned on subsequent calls without any changes
             assertThat(fact.getObject(), is((DataSource) ds));
    -        verify(ds, config, jndi);
    +        verify(ds, config);
     
             // Check that destruction properly closes the DataSource
             reset(ds);
    @@ -107,7 +107,8 @@ protected BasicDataSource createBasicDataSource() {
         public void testJNDI() throws Exception {
             DataSource ds = EasyMock.createMock(DataSource.class);
             JDBCConfigProperties config = EasyMock.createMock(JDBCConfigProperties.class);
    -        Context jndi = EasyMock.createMock(Context.class);
    +        InitialContext jndi = EasyMock.createMock(InitialContext.class);
    +        GeoTools.init(jndi);
     
             expect(config.isEnabled()).andReturn(true);
             expectJndi(config, "java:comp/env/jdbc/test");
    @@ -118,7 +119,7 @@ public void testJNDI() throws Exception {
             expectVerifyConnect(ds);
             replay(ds, config, jndi);
     
    -        DataSourceFactoryBean fact = new DataSourceFactoryBean(config, jndi);
    +        DataSourceFactoryBean fact = new DataSourceFactoryBean(config);
     
             // Check that we get the DataSource
             assertThat(fact.getObject(), is((DataSource) ds));
    @@ -143,7 +144,8 @@ public void testJNDI() throws Exception {
         public void testJNDIFail() throws Exception {
             final BasicDataSource ds = EasyMock.createMock(BasicDataSource.class);
             JDBCConfigProperties config = EasyMock.createMock(JDBCConfigProperties.class);
    -        Context jndi = EasyMock.createMock(Context.class);
    +        InitialContext jndi = EasyMock.createMock(InitialContext.class);
    +        GeoTools.init(jndi);
     
             expect(config.isEnabled()).andReturn(true);
             expectJndi(config, "java:comp/env/jdbc/test");
    @@ -190,7 +192,7 @@ public void testJNDIFail() throws Exception {
             replay(ds, config, jndi);
     
             DataSourceFactoryBean fact =
    -                new DataSourceFactoryBean(config, jndi) {
    +                new DataSourceFactoryBean(config) {
     
                         @Override
                         protected BasicDataSource createBasicDataSource() {
    
  • src/community/taskmanager/core/src/main/java/org/geoserver/taskmanager/external/impl/PostgisJndiDbSourceImpl.java+1 10 modified
    @@ -11,7 +11,6 @@
     import java.sql.SQLException;
     import java.util.HashMap;
     import java.util.Map;
    -import javax.naming.Context;
     import javax.naming.NamingException;
     import javax.sql.DataSource;
     import org.geoserver.taskmanager.external.DbSource;
    @@ -58,17 +57,9 @@ public void setSchema(String schema) {
     
         @Override
         public DataSource getDataSource() throws SQLException {
    -        Context ctx = null;
             DataSource ds = null;
    -
    -        try {
    -            ctx = GeoTools.getInitialContext(GeoTools.getDefaultHints());
    -        } catch (NamingException e) {
    -            throw new IllegalStateException(e);
    -        }
    -
             try {
    -            ds = (DataSource) ctx.lookup(jndiName);
    +            ds = (DataSource) GeoTools.jndiLookup(jndiName);
             } catch (NamingException e) {
                 throw new SQLException(e);
             }
    
  • src/security/jdbc/src/main/java/org/geoserver/security/jdbc/AbstractJDBCService.java+2 4 modified
    @@ -18,8 +18,6 @@
     import java.util.Properties;
     import java.util.StringTokenizer;
     import java.util.logging.Logger;
    -import javax.naming.Context;
    -import javax.naming.InitialContext;
     import javax.naming.NamingException;
     import javax.sql.DataSource;
     import org.apache.commons.dbcp.BasicDataSource;
    @@ -31,6 +29,7 @@
     import org.geoserver.security.impl.AbstractGeoServerSecurityService;
     import org.geoserver.security.jdbc.config.JDBCSecurityServiceConfig;
     import org.geoserver.util.IOUtils;
    +import org.geotools.util.factory.GeoTools;
     
     /**
      * JDBC base implementation for common used methods
    @@ -56,8 +55,7 @@ public void initializeDSFromConfig(SecurityNamedServiceConfig namedConfig) throw
             if (config.isJndi()) {
                 String jndiName = config.getJndiName();
                 try {
    -                Context initialContext = new InitialContext();
    -                datasource = (DataSource) initialContext.lookup(jndiName);
    +                datasource = (DataSource) GeoTools.jndiLookup(jndiName);
                 } catch (NamingException e) {
                     throw new IOException(e);
                 }
    
  • src/web/security/jdbc/src/main/java/org/geoserver/security/web/jdbc/JDBCConnectionPanel.java+12 11 modified
    @@ -10,8 +10,6 @@
     import java.sql.DriverManager;
     import java.util.logging.Level;
     import java.util.logging.Logger;
    -import javax.naming.Context;
    -import javax.naming.InitialContext;
     import javax.sql.DataSource;
     import org.apache.wicket.ajax.AjaxRequestTarget;
     import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
    @@ -27,6 +25,7 @@
     import org.apache.wicket.model.Model;
     import org.apache.wicket.model.StringResourceModel;
     import org.geoserver.security.jdbc.config.JDBCSecurityServiceConfig;
    +import org.geotools.util.factory.GeoTools;
     import org.geotools.util.logging.Logging;
     
     /**
    @@ -179,16 +178,18 @@ public void test() throws Exception {
                 // models
                 ((FormComponent) get("jndiName")).processInput();
     
    -            Context initialContext = new InitialContext();
    -            try {
    -                DataSource datasource =
    -                        (DataSource)
    -                                initialContext.lookup(
    -                                        get("jndiName").getDefaultModelObjectAsString());
    -                try (Connection con = datasource.getConnection()) {}
    -            } finally {
    -                initialContext.close();
    +            Object lookedUp = GeoTools.jndiLookup(get("jndiName").getDefaultModelObjectAsString());
    +            if (lookedUp == null)
    +                throw new IllegalArgumentException(
    +                        "Failed to look up an object from JNDI at the given location");
    +            if (!(lookedUp instanceof DataSource)) {
    +                LOGGER.log(
    +                        Level.WARNING,
    +                        "Was trying to look up a DataSource in JNDI, but got this instead: "
    +                                + lookedUp);
    +                throw new IllegalArgumentException("JNDI lookup did not provide a DataSource");
                 }
    +            try (Connection con = ((DataSource) lookedUp).getConnection()) {}
             }
         }
     }
    

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

4

News mentions

0

No linked articles in our index yet.