VYPR
Moderate severityNVD Advisory· Published Mar 20, 2024· Updated Aug 1, 2024

GeoServer Stored Cross-Site Scripting (XSS) vulnerability in MapML HTML Page

CVE-2024-23819

Description

GeoServer is an open source software server written in Java that allows users to share and edit geospatial data. A stored cross-site scripting (XSS) vulnerability exists in versions prior to 2.23.4 and 2.24.1 that enables an authenticated administrator with workspace-level privileges to store a JavaScript payload in the GeoServer catalog that will execute in the context of another user's browser when viewed in the MapML HTML Page. The MapML extension must be installed and access to the MapML HTML Page is available to all users although data security may limit users' ability to trigger the XSS. Versions 2.23.4 and 2.24.1 contain a patch for this issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.geoserver.extension:gs-mapmlMaven
< 2.23.42.23.4
org.geoserver.extension:gs-mapmlMaven
>= 2.24.0, < 2.24.12.24.1

Affected products

1

Patches

2
6f04adbdc6c2

[GEOS-11154] Improve handling special characters in the MapML HTML Page

https://github.com/geoserver/geoserverSteve IkeokaOct 10, 2023via ghsa
2 files changed · +36 5
  • src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLController.java+5 5 modified
    @@ -5,6 +5,7 @@
     
     package org.geoserver.mapml;
     
    +import static org.apache.commons.text.StringEscapeUtils.escapeHtml4;
     import static org.geoserver.mapml.MapMLConstants.MAPML_MIME_TYPE;
     
     import java.io.IOException;
    @@ -186,13 +187,12 @@ public String Html(
                             "/mapml/viewer/widget/mapml-viewer.js",
                             null,
                             URLMangler.URLType.RESOURCE);
    -        String title = layerLabel;
             StringBuilder sb = new StringBuilder();
             sb.append("<!DOCTYPE html>\n")
                     .append("<html>\n")
                     .append("<head>\n")
                     .append("<title>")
    -                .append(title)
    +                .append(escapeHtml4(layerLabel))
                     .append("</title>\n")
                     .append("<meta charset='utf-8'>\n")
                     .append("<script type=\"module\"  src=\"")
    @@ -225,17 +225,17 @@ public String Html(
                     .append(longitude)
                     .append("\" controls controlslist=\"geolocation\">\n")
                     .append("<layer- label=\"")
    -                .append(layerLabel)
    +                .append(escapeHtml4(layerLabel))
                     .append("\" ")
                     .append("src=\"")
                     .append(request.getContextPath())
                     .append(request.getServletPath())
                     .append("/")
    -                .append(layer)
    +                .append(escapeHtml4(layer))
                     .append("/")
                     .append(proj)
                     .append("/")
    -                .append(!styleName.isEmpty() ? "?style=" + styleName : "")
    +                .append(!styleName.isEmpty() ? "?style=" + escapeHtml4(styleName) : "")
                     .append("\" checked></layer->\n")
                     .append("</mapml-viewer>\n")
                     .append("</body>\n")
    
  • src/extension/mapml/src/test/java/org/geoserver/mapml/MapMLControllerTest.java+31 0 modified
    @@ -6,6 +6,9 @@
     
     import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
     import static org.geowebcache.grid.GridSubsetFactory.createGridSubSet;
    +import static org.hamcrest.MatcherAssert.assertThat;
    +import static org.hamcrest.Matchers.containsString;
    +import static org.hamcrest.Matchers.not;
     import static org.junit.Assert.assertEquals;
     import static org.junit.Assert.assertFalse;
     import static org.junit.Assert.assertNotNull;
    @@ -243,6 +246,34 @@ public void testHTML() throws Exception {
                     "layerGroup".equalsIgnoreCase(d.title()));
         }
     
    +    @Test
    +    public void testEscaping() throws Exception {
    +        String unescapedTitle = "title\"><";
    +        String escapedTitle = "title&quot;&gt;&lt;";
    +        Catalog catalog = getCatalog();
    +        LayerGroupInfo lg = catalog.getLayerGroupByName("layerGroup");
    +        MockHttpServletRequest request = createRequest("mapml/" + lg.getName() + "/osmtile");
    +        MockHttpServletResponse response = new MockHttpServletResponse();
    +        try {
    +            lg.setTitle(unescapedTitle);
    +            catalog.save(lg);
    +            String htmlResponse =
    +                    mc.Html(
    +                            request,
    +                            response,
    +                            lg.getName(),
    +                            "osmtile",
    +                            Optional.empty(),
    +                            Optional.empty(),
    +                            Optional.empty());
    +            assertThat(htmlResponse, not(containsString(unescapedTitle)));
    +            assertThat(htmlResponse, containsString(escapedTitle));
    +        } finally {
    +            lg.setTitle(null);
    +            catalog.save(lg);
    +        }
    +    }
    +
         @Test
         public void testNonExistentLayer() throws Exception {
             MockHttpServletRequest request = createRequest("mapml/" + "foo" + "/osmtile");
    
df65ff05250c

[GEOS-11154] Improve handling special characters in the MapML HTML Page

https://github.com/geoserver/geoserverSteve IkeokaOct 10, 2023via ghsa
2 files changed · +36 5
  • src/extension/mapml/src/main/java/org/geoserver/mapml/MapMLController.java+5 5 modified
    @@ -5,6 +5,7 @@
     
     package org.geoserver.mapml;
     
    +import static org.apache.commons.text.StringEscapeUtils.escapeHtml4;
     import static org.geoserver.mapml.MapMLConstants.MAPML_MIME_TYPE;
     
     import java.io.IOException;
    @@ -186,13 +187,12 @@ public String Html(
                             "/mapml/viewer/widget/mapml-viewer.js",
                             null,
                             URLMangler.URLType.RESOURCE);
    -        String title = layerLabel;
             StringBuilder sb = new StringBuilder();
             sb.append("<!DOCTYPE html>\n")
                     .append("<html>\n")
                     .append("<head>\n")
                     .append("<title>")
    -                .append(title)
    +                .append(escapeHtml4(layerLabel))
                     .append("</title>\n")
                     .append("<meta charset='utf-8'>\n")
                     .append("<script type=\"module\"  src=\"")
    @@ -225,17 +225,17 @@ public String Html(
                     .append(longitude)
                     .append("\" controls controlslist=\"geolocation\">\n")
                     .append("<layer- label=\"")
    -                .append(layerLabel)
    +                .append(escapeHtml4(layerLabel))
                     .append("\" ")
                     .append("src=\"")
                     .append(request.getContextPath())
                     .append(request.getServletPath())
                     .append("/")
    -                .append(layer)
    +                .append(escapeHtml4(layer))
                     .append("/")
                     .append(proj)
                     .append("/")
    -                .append(!styleName.isEmpty() ? "?style=" + styleName : "")
    +                .append(!styleName.isEmpty() ? "?style=" + escapeHtml4(styleName) : "")
                     .append("\" checked></layer->\n")
                     .append("</mapml-viewer>\n")
                     .append("</body>\n")
    
  • src/extension/mapml/src/test/java/org/geoserver/mapml/MapMLControllerTest.java+31 0 modified
    @@ -6,6 +6,9 @@
     
     import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
     import static org.geowebcache.grid.GridSubsetFactory.createGridSubSet;
    +import static org.hamcrest.MatcherAssert.assertThat;
    +import static org.hamcrest.Matchers.containsString;
    +import static org.hamcrest.Matchers.not;
     import static org.junit.Assert.assertEquals;
     import static org.junit.Assert.assertFalse;
     import static org.junit.Assert.assertNotNull;
    @@ -243,6 +246,34 @@ public void testHTML() throws Exception {
                     "layerGroup".equalsIgnoreCase(d.title()));
         }
     
    +    @Test
    +    public void testEscaping() throws Exception {
    +        String unescapedTitle = "title\"><";
    +        String escapedTitle = "title&quot;&gt;&lt;";
    +        Catalog catalog = getCatalog();
    +        LayerGroupInfo lg = catalog.getLayerGroupByName("layerGroup");
    +        MockHttpServletRequest request = createRequest("mapml/" + lg.getName() + "/osmtile");
    +        MockHttpServletResponse response = new MockHttpServletResponse();
    +        try {
    +            lg.setTitle(unescapedTitle);
    +            catalog.save(lg);
    +            String htmlResponse =
    +                    mc.Html(
    +                            request,
    +                            response,
    +                            lg.getName(),
    +                            "osmtile",
    +                            Optional.empty(),
    +                            Optional.empty(),
    +                            Optional.empty());
    +            assertThat(htmlResponse, not(containsString(unescapedTitle)));
    +            assertThat(htmlResponse, containsString(escapedTitle));
    +        } finally {
    +            lg.setTitle(null);
    +            catalog.save(lg);
    +        }
    +    }
    +
         @Test
         public void testNonExistentLayer() throws Exception {
             MockHttpServletRequest request = createRequest("mapml/" + "foo" + "/osmtile/");
    

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

7

News mentions

0

No linked articles in our index yet.