Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package mapserver for openSUSE:Factory 
checked in at 2026-07-13 14:26:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mapserver (Old)
 and      /work/SRC/openSUSE:Factory/.mapserver.new.1991 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mapserver"

Mon Jul 13 14:26:03 2026 rev:14 rq:1365155 version:8.6.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/mapserver/mapserver.changes      2026-05-29 
18:08:47.822569209 +0200
+++ /work/SRC/openSUSE:Factory/.mapserver.new.1991/mapserver.changes    
2026-07-13 14:26:20.135865301 +0200
@@ -1,0 +2,19 @@
+Sun Jul 12 14:55:27 UTC 2026 - Jan Engelhardt <[email protected]>
+
+- Update to release 8.6.5
+  * Properly escape mapserv_onlineresource in OpenLayers viewer
+    with WMS
+  * PostGIS: make sure identifier value is numeric when the
+    declared type is numeric too
+  * OGC API Features: validate offset before rendering to fix
+    reflected XSS
+  * WCS POST: NULL-Dereference Denial of Service When `BoundingBox`
+    Omits `crs`
+  * Reflected XSS in WMS OpenLayers output via the
+    `X-Forwarded-Host` header
+  * Heap buffer overflow in WMS GetLegendGraphic via repeated LAYER
+    parameters
+  * msMySQLJoinNext(): prevent SQL injection
+  * msPOSTGRESQLJoinNext(): avoid potential SQL injection
+
+-------------------------------------------------------------------

Old:
----
  mapserver-8.6.3.tar.gz

New:
----
  mapserver-8.6.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mapserver.spec ++++++
--- /var/tmp/diff_new_pack.GyZ5RB/_old  2026-07-13 14:26:22.855958304 +0200
+++ /var/tmp/diff_new_pack.GyZ5RB/_new  2026-07-13 14:26:22.855958304 +0200
@@ -33,7 +33,7 @@
 %{?sle15_python_module_pythons}
 
 Name:           mapserver
-Version:        8.6.3
+Version:        8.6.5
 Release:        0
 Summary:        Environment for building spatially-enabled internet 
applications
 License:        MIT

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.GyZ5RB/_old  2026-07-13 14:26:22.883959261 +0200
+++ /var/tmp/diff_new_pack.GyZ5RB/_new  2026-07-13 14:26:22.903959945 +0200
@@ -1,5 +1,5 @@
-mtime: 1780027572
-commit: 1b845d6d9e38b8c7107ede08ca144e61f7d83be50fe01edc2e4db97a7020d2f1
+mtime: 1783869242
+commit: 27ee9a28a81ad7795d28578db26017fac0a6f1373ec9553259edb1294f0ada42
 url: https://src.opensuse.org/jengelh/mapserver
 revision: master
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-07-12 17:14:02.000000000 +0200
@@ -0,0 +1 @@
+.osc

++++++ mapserver-8.6.3.tar.gz -> mapserver-8.6.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/.github/workflows/start.sh 
new/mapserver-8.6.5/.github/workflows/start.sh
--- old/mapserver-8.6.3/.github/workflows/start.sh      2026-05-07 
14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/.github/workflows/start.sh      2026-07-10 
19:20:43.000000000 +0200
@@ -190,4 +190,11 @@
 MAPSERVER_CONFIG_FILE=/tmp/mapserver.conf mapserv 
QUERY_STRING="MAP=wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > 
/tmp/res.txt
 cat /tmp/res.txt | grep "Web application error" >/dev/null || (cat 
/tmp/res.txt && /bin/false)
 
+# Check 
https://github.com/MapServer/MapServer/security/advisories/GHSA-xqj6-vjqr-33vv
+MAPSERVER_CONFIG_FILE=${WORK_DIR}/msautotest/etc/mapserv.conf 
SCRIPT_NAME=mapserv SERVER_PORT=80 HTTP_X_FORWARDED_HOST="with'single'quote" 
mapserv 
QUERY_STRING="MAP=wms_simple_no_onlineresource.map&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-67.5725,42.3683,-58.9275,48.13&FORMAT=application/openlayers&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road"
 > /tmp/res.txt
+# We need to escape backslash once for the grep regexp, and once for the 
shell...
+# Hence 4 backslashes for one in the actual output
+cat /tmp/res.txt | grep "with\\\\'single\\\\'quote" >/dev/null || (cat 
/tmp/res.txt && /bin/false)
+
+
 echo "Done !"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/CITATION.cff 
new/mapserver-8.6.5/CITATION.cff
--- old/mapserver-8.6.3/CITATION.cff    2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/CITATION.cff    2026-07-10 19:20:43.000000000 +0200
@@ -1,8 +1,8 @@
 cff-version: 1.2.0
 title: MapServer
 message: If you use this software, please cite it using the metadata from this 
file.
-version: 8.6.3
-date-released: 2026-05-07
+version: 8.6.5
+date-released: 2026-07-10
 abstract: MapServer is an Open Source platform for publishing spatial data and 
interactive mapping applications to the web.
 type: software
 authors:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/CMakeLists.txt 
new/mapserver-8.6.5/CMakeLists.txt
--- old/mapserver-8.6.3/CMakeLists.txt  2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/CMakeLists.txt  2026-07-10 19:20:43.000000000 +0200
@@ -17,7 +17,7 @@
 
 set (MapServer_VERSION_MAJOR 8)
 set (MapServer_VERSION_MINOR 6)
-set (MapServer_VERSION_REVISION 3)
+set (MapServer_VERSION_REVISION 5)
 set (MapServer_VERSION_SUFFIX "")
 
 # Set C++ version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/HISTORY.md 
new/mapserver-8.6.5/HISTORY.md
--- old/mapserver-8.6.3/HISTORY.md      2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/HISTORY.md      2026-07-10 19:20:43.000000000 +0200
@@ -13,6 +13,28 @@
 
 The online Migration Guide can be found at 
https://mapserver.org/MIGRATION_GUIDE.html
 
+8.6.5 release (2026-07-10)
+--------------------------
+
+- security: OGC API Features: validate offset before rendering to fix 
reflected XSS (#7573)
+
+- security: WCS POST: NULL-Dereference Denial of Service When `BoundingBox` 
Omits `crs` (#7556)
+
+- security: Reflected XSS in WMS OpenLayers output via the `X-Forwarded-Host` 
header (#7544)
+
+- security: Heap buffer overflow in WMS GetLegendGraphic via repeated LAYER 
parameters (#7555)
+
+- security: msMySQLJoinNext(): prevent SQL injection (#7547)
+
+- security: msPOSTGRESQLJoinNext(): avoid potential SQL injection (#7546)
+
+8.6.4 release (2026-06-01)
+--------------------------
+
+- security: properly escape mapserv_onlineresource in OpenLayers viewer with 
WMS (#7517)
+
+- security: PostGIS: make sure identifier value is numeric when the declared 
type is numeric too (#7516)
+
 8.6.3 release (2026-05-07)
 --------------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/SECURITY.md 
new/mapserver-8.6.5/SECURITY.md
--- old/mapserver-8.6.3/SECURITY.md     2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/SECURITY.md     2026-07-10 19:20:43.000000000 +0200
@@ -10,6 +10,13 @@
 Please follow the general guidelines for bug 
 submissions, when describing the vulnerability (see 
https://mapserver.org/development/bugs.html).
 
+## Note about use of AI/LLM/automated scanners
+
+While reporters are free to use any tool of their choice to detect issues, they
+must *manually* confirm the findings of those tools with an actual reproducing
+test case, not just a theoretical analysis.
+The report must also be humanly checked and be kept as succint as possible.
+
 ## Supported Versions
 
 The MapServer PSC (Project Steering Committee) will release patches for 
security vulnerabilities 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/apps/mapserv.c 
new/mapserver-8.6.5/src/apps/mapserv.c
--- old/mapserver-8.6.3/src/apps/mapserv.c      2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/apps/mapserv.c      2026-07-10 19:20:43.000000000 
+0200
@@ -60,6 +60,14 @@
 static void msCleanupOnSignal(int nInData) {
   (void)nInData;
   finish_process = 1;
+#ifdef USE_FASTCGI
+  /* Ask libfcgi to stop accepting new requests. This causes a blocked
+   * FCGI_Accept() to return -1, so the main loop can exit promptly
+   * instead of waiting for the next request to arrive. Safe to call
+   * from a signal handler: it just sets an internal flag (declared in
+   * fcgiapp.h, which is pulled in via fcgi_stdio.h above). */
+  FCGX_ShutdownPending();
+#endif
 }
 #endif
 
@@ -242,8 +250,22 @@
   /*      Setup cleanup magic, mainly for FastCGI case.                   */
   /* -------------------------------------------------------------------- */
 #ifndef _WIN32
-  signal(SIGUSR1, msCleanupOnSignal);
-  signal(SIGTERM, msCleanupOnSignal);
+  {
+    /* Install via sigaction without SA_RESTART so that a blocking
+     * accept()/select() inside FCGI_Accept() returns EINTR when the
+     * signal arrives while the process is idle. Combined with
+     * FCGX_ShutdownPending() in the handler, this lets the FastCGI
+     * loop exit on SIGTERM instead of waiting for the next request. */
+    struct sigaction sa;
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_handler = msCleanupOnSignal;
+    sigemptyset(&sa.sa_mask);
+    sigaddset(&sa.sa_mask, SIGUSR1);
+    sigaddset(&sa.sa_mask, SIGTERM);
+    sa.sa_flags = 0; /* deliberately no SA_RESTART */
+    sigaction(SIGUSR1, &sa, NULL);
+    sigaction(SIGTERM, &sa, NULL);
+  }
 #endif
 
 #ifdef USE_FASTCGI
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/cgiutil.c 
new/mapserver-8.6.5/src/cgiutil.c
--- old/mapserver-8.6.3/src/cgiutil.c   2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/cgiutil.c   2026-07-10 19:20:43.000000000 +0200
@@ -396,22 +396,37 @@
   }
 }
 
-char x2c(char *what) {
-  register char digit;
-
-  digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
-  digit *= 16;
-  digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
-  return (digit);
+static int hex_to_integer(char c) {
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  if (c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  if (c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  return -1;
 }
 
 void unescape_url(char *url) {
-  register int x, y;
+  register int x, y, hi, lo;
 
   for (x = 0, y = 0; url[y]; ++x, ++y) {
-    if ((url[x] = url[y]) == '%') {
-      url[x] = x2c(&url[y + 1]);
+    if (url[y] == '%') {
+      hi = hex_to_integer(url[y + 1]);
+      if (hi < 0) {
+        /* %-encoding is malformed, leave as-is */
+        url[x] = '%';
+        continue;
+      }
+      lo = hex_to_integer(url[y + 2]);
+      if (lo < 0) {
+        /* %-encoding is malformed, leave as-is */
+        url[x] = '%';
+        continue;
+      }
+      url[x] = (char)(hi * 16 + lo);
       y += 2;
+    } else {
+      url[x] = url[y];
     }
   }
   url[x] = '\0';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/cgiutil.h 
new/mapserver-8.6.5/src/cgiutil.h
--- old/mapserver-8.6.3/src/cgiutil.h   2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/cgiutil.h   2026-07-10 19:20:43.000000000 +0200
@@ -93,7 +93,6 @@
 MS_DLL_EXPORT char *makeword_skip(char *, char, char);
 MS_DLL_EXPORT char *makeword(char *, char);
 MS_DLL_EXPORT char *fmakeword(FILE *, char, int *);
-MS_DLL_EXPORT char x2c(char *);
 MS_DLL_EXPORT void unescape_url(char *);
 MS_DLL_EXPORT void plustospace(char *);
 MS_DLL_EXPORT int rind(char *, char);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/flatgeobuf/flatgeobuf_c.cpp 
new/mapserver-8.6.5/src/flatgeobuf/flatgeobuf_c.cpp
--- old/mapserver-8.6.3/src/flatgeobuf/flatgeobuf_c.cpp 2026-05-07 
14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/flatgeobuf/flatgeobuf_c.cpp 2026-07-10 
19:20:43.000000000 +0200
@@ -15,15 +15,21 @@
 uint32_t INIT_BUFFER_SIZE = 1024 * 4;
 
 template <typename T>
-void parse_value(uint8_t *data, char **values, uint16_t i, uint32_t &offset, 
bool found)
+bool parse_value(uint8_t *data, uint32_t size, char **values, uint16_t i, 
uint32_t &offset, bool found)
 {
     using std::to_string;
+    if (sizeof(T) > size - offset)
+    {
+        msSetError(MS_FGBERR, "Invalid size for property value", 
"flatgeobuf_decode_properties");
+        return false;
+    }
     if (found)
     {
         msFree(values[i]);
         values[i] = msStrdup(to_string(*((T*) (data + offset))).c_str());
     }
     offset += sizeof(T);
+    return true;
 }
 
 ctx *flatgeobuf_init_ctx()
@@ -139,7 +145,8 @@
     if (properties && properties->size() != 0) {
         ctx->properties = (uint8_t *) properties->data();
         ctx->properties_size = properties->size();
-        flatgeobuf_decode_properties(ctx, layer, shape);
+        if (flatgeobuf_decode_properties(ctx, layer, shape) == -1)
+            return -1;
     } else {
         ctx->properties_size = 0;
     }
@@ -183,47 +190,51 @@
                type = column.type;
                switch (type) {
                case flatgeobuf_column_type_bool:
-            parse_value<uint8_t>(data, values, ii, offset, found);
+            if (!parse_value<uint8_t>(data, size, values, ii, offset, found)) 
return -1;
                        break;
                case flatgeobuf_column_type_byte:
-            parse_value<int8_t>(data, values, ii, offset, found);
+            if (!parse_value<int8_t>(data, size, values, ii, offset, found)) 
return -1;
                        break;
                case flatgeobuf_column_type_ubyte:
-            parse_value<uint8_t>(data, values, ii, offset, found);
+            if (!parse_value<uint8_t>(data, size, values, ii, offset, found)) 
return -1;
                        break;
                case flatgeobuf_column_type_short:
-                       parse_value<int16_t>(data, values, ii, offset, found);
+                       if (!parse_value<int16_t>(data, size, values, ii, 
offset, found)) return -1;
                        break;
                case flatgeobuf_column_type_ushort:
-            parse_value<uint16_t>(data, values, ii, offset, found);
+            if (!parse_value<uint16_t>(data, size, values, ii, offset, found)) 
return -1;
                        break;
                case flatgeobuf_column_type_int:
-            parse_value<int32_t>(data, values, ii, offset, found);
+            if (!parse_value<int32_t>(data, size, values, ii, offset, found)) 
return -1;
             break;
                case flatgeobuf_column_type_uint:
-                       parse_value<uint32_t>(data, values, ii, offset, found);
+                       if (!parse_value<uint32_t>(data, size, values, ii, 
offset, found)) return -1;
                        break;
                case flatgeobuf_column_type_long:
-            parse_value<int64_t>(data, values, ii, offset, found);
+            if (!parse_value<int64_t>(data, size, values, ii, offset, found)) 
return -1;
             break;
                case flatgeobuf_column_type_ulong:
-                       parse_value<uint64_t>(data, values, ii, offset, found);
+                       if (!parse_value<uint64_t>(data, size, values, ii, 
offset, found)) return -1;
                        break;
                case flatgeobuf_column_type_float:
-            parse_value<float>(data, values, ii, offset, found);
+            if (!parse_value<float>(data, size, values, ii, offset, found)) 
return -1;
                        break;
                case flatgeobuf_column_type_double:
-                       parse_value<double>(data, values, ii, offset, found);
+                       if (!parse_value<double>(data, size, values, ii, 
offset, found)) return -1;
                        break;
         case flatgeobuf_column_type_datetime:
                case flatgeobuf_column_type_string: {
                        uint32_t len;
-                       if (offset + sizeof(len) > size){
+                       if (sizeof(len) > size - offset){
                 msSetError(MS_FGBERR, "Invalid size for string value", 
"flatgeobuf_decode_properties");
                 return -1;
             }
                        memcpy(&len, data + offset, sizeof(uint32_t));
                        offset += sizeof(len);
+                       if (len > size - offset){
+                msSetError(MS_FGBERR, "Invalid size for string value", 
"flatgeobuf_decode_properties");
+                return -1;
+            }
                        if (found) {
                 char *str = (char *) msSmallMalloc(len + 1);
                 memcpy(str, data + offset, len);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapimageio.c 
new/mapserver-8.6.5/src/mapimageio.c
--- old/mapserver-8.6.3/src/mapimageio.c        2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mapimageio.c        2026-07-10 19:20:43.000000000 
+0200
@@ -860,6 +860,17 @@
   }
 }
 
+/* release the giflib handle, ignoring the close status */
+static void closeGIF(GifFileType *image) {
+#if defined GIFLIB_MAJOR && GIFLIB_MINOR &&                                    
\
+    ((GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || (GIFLIB_MAJOR > 5))
+  int errcode;
+  DGifCloseFile(image, &errcode);
+#else
+  DGifCloseFile(image);
+#endif
+}
+
 /* not fully implemented and tested */
 /* missing: set the first pointer to a,r,g,b */
 int readGIF(char *path, rasterBufferObj *rb) {
@@ -905,11 +916,24 @@
   a = rb->data.rgba.a = &rb->data.rgba.pixels[3];
 
   cmap = (image->Image.ColorMap) ? image->Image.ColorMap : image->SColorMap;
+  if (cmap == NULL) {
+    msSetError(MS_MISCERR, "gif image has no color map", "readGIF()");
+    free(rb->data.rgba.pixels);
+    rb->data.rgba.pixels = NULL;
+    closeGIF(image);
+    return MS_FAILURE;
+  }
+  /* the background index is read straight from the file and may point past
+     the end of the color table */
+  const int bgIndex = (image->SBackGroundColor >= 0 &&
+                       image->SBackGroundColor < cmap->ColorCount)
+                          ? image->SBackGroundColor
+                          : 0;
   for (unsigned i = 0; i < rb->width * rb->height; i++) {
     *a = 255;
-    *r = cmap->Colors[image->SBackGroundColor].Red;
-    *g = cmap->Colors[image->SBackGroundColor].Green;
-    *b = cmap->Colors[image->SBackGroundColor].Blue;
+    *r = cmap->Colors[bgIndex].Red;
+    *g = cmap->Colors[bgIndex].Green;
+    *b = cmap->Colors[bgIndex].Blue;
     a += rb->data.rgba.pixel_step;
     r += rb->data.rgba.pixel_step;
     g += rb->data.rgba.pixel_step;
@@ -955,6 +979,9 @@
           msSetError(MS_MISCERR,
                      "corrupted gif image, img size exceeds screen size",
                      "readGIF()");
+          free(rb->data.rgba.pixels);
+          rb->data.rgba.pixels = NULL;
+          closeGIF(image);
           return MS_FAILURE;
         }
 
@@ -983,7 +1010,8 @@
 
               for (unsigned j = 0; j < width; j++) {
                 GifPixelType pix = line[j];
-                if (transIdx == -1 || pix != transIdx) {
+                if ((transIdx == -1 || pix != transIdx) &&
+                    pix < cmap->ColorCount) {
                   *a = 255;
                   *r = cmap->Colors[pix].Red;
                   *g = cmap->Colors[pix].Green;
@@ -1018,7 +1046,8 @@
             }
             for (unsigned j = 0; j < width; j++) {
               GifPixelType pix = line[j];
-              if (transIdx == -1 || pix != transIdx) {
+              if ((transIdx == -1 || pix != transIdx) &&
+                  pix < cmap->ColorCount) {
                 *a = 255;
                 *r = cmap->Colors[pix].Red;
                 *g = cmap->Colors[pix].Green;
@@ -1102,25 +1131,7 @@
 
   } while (recordType != TERMINATE_RECORD_TYPE);
 
-#if defined GIFLIB_MAJOR && GIFLIB_MINOR &&                                    
\
-    ((GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || (GIFLIB_MAJOR > 5))
-  if (DGifCloseFile(image, &errcode) == GIF_ERROR) {
-    msSetError(MS_MISCERR, "failed to close gif after loading: %s", 
"readGIF()",
-               gif_error_msg(errcode));
-    return MS_FAILURE;
-  }
-#else
-  if (DGifCloseFile(image) == GIF_ERROR) {
-#if defined GIFLIB_MAJOR && GIFLIB_MAJOR >= 5
-    msSetError(MS_MISCERR, "failed to close gif after loading: %s", 
"readGIF()",
-               gif_error_msg(image->Error));
-#else
-    msSetError(MS_MISCERR, "failed to close gif after loading: %s", 
"readGIF()",
-               gif_error_msg());
-#endif
-    return MS_FAILURE;
-  }
-#endif
+  closeGIF(image);
 
   return MS_SUCCESS;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapjoin.c 
new/mapserver-8.6.5/src/mapjoin.c
--- old/mapserver-8.6.3/src/mapjoin.c   2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/mapjoin.c   2026-07-10 19:20:43.000000000 +0200
@@ -808,8 +808,22 @@
   /* if(strcmp(joininfo->target, msMySQLReadStringAttribute(joininfo->conn, i,
    * joininfo->toindex)) == 0) break; */
   /* }   */
-  snprintf(qbuf, sizeof(qbuf), "SELECT * FROM %s WHERE %s = %s", join->table,
-           joininfo->tocolumn, joininfo->target);
+
+  char *endptr = NULL;
+  (void)strtoll(joininfo->target, &endptr, 10);
+  if (endptr != joininfo->target + strlen(joininfo->target)) {
+    msSetError(MS_JOINERR,
+               "Non-numeric value in MySQL JOIN colunn not supported.",
+               "msMySQLJoinNext()");
+    return (MS_FAILURE);
+  }
+
+  char *escapedTableName = msReplaceSubstring(join->table, "`", "``");
+  char *escapedToColumn = msReplaceSubstring(joininfo->tocolumn, "`", "``");
+  snprintf(qbuf, sizeof(qbuf), "SELECT * FROM `%s` WHERE `%s` = %s",
+           escapedTableName, escapedToColumn, joininfo->target);
+  msFree(escapedTableName);
+  msFree(escapedToColumn);
   MYDEBUG printf("%s<BR>\n", qbuf);
   if ((joininfo->qresult =
            msMySQLQuery(qbuf, joininfo->conn))) { /* There were some rows 
found,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/maplayer.c 
new/mapserver-8.6.5/src/maplayer.c
--- old/mapserver-8.6.3/src/maplayer.c  2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/maplayer.c  2026-07-10 19:20:43.000000000 +0200
@@ -2254,33 +2254,41 @@
 /*                                                                      */
 /*      Return the property name in a properly escaped and quoted form. */
 /************************************************************************/
-char *LayerDefaultEscapePropertyName(layerObj *layer, const char *pszString) {
+
+char *msDefaultEscapePropertyName(const char *pszString) {
   char *pszEscapedStr = NULL;
   int i, j = 0;
 
-  if (layer && pszString && strlen(pszString) > 0) {
-    int nLength = strlen(pszString);
+  int nLength = strlen(pszString);
 
-    pszEscapedStr = (char *)msSmallMalloc(1 + 2 * nLength + 1 + 1);
-    pszEscapedStr[j++] = '"';
+  pszEscapedStr = (char *)msSmallMalloc(1 + 2 * nLength + 1 + 1);
+  pszEscapedStr[j++] = '"';
 
-    for (i = 0; i < nLength; i++) {
-      char c = pszString[i];
-      if (c == '"') {
-        pszEscapedStr[j++] = '"';
-        pszEscapedStr[j++] = '"';
-      } else if (c == '\\') {
-        pszEscapedStr[j++] = '\\';
-        pszEscapedStr[j++] = '\\';
-      } else
-        pszEscapedStr[j++] = c;
-    }
-    pszEscapedStr[j++] = '"';
-    pszEscapedStr[j++] = 0;
+  for (i = 0; i < nLength; i++) {
+    char c = pszString[i];
+    if (c == '"') {
+      pszEscapedStr[j++] = '"';
+      pszEscapedStr[j++] = '"';
+    } else if (c == '\\') {
+      pszEscapedStr[j++] = '\\';
+      pszEscapedStr[j++] = '\\';
+    } else
+      pszEscapedStr[j++] = c;
   }
+  pszEscapedStr[j++] = '"';
+  pszEscapedStr[j++] = 0;
+
   return pszEscapedStr;
 }
 
+static char *LayerDefaultEscapePropertyName(layerObj *layer,
+                                            const char *pszString) {
+  if (layer && pszString && strlen(pszString) > 0) {
+    return msDefaultEscapePropertyName(pszString);
+  }
+  return NULL;
+}
+
 /*
  * msConnectLayer
  *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapogcapi.cpp 
new/mapserver-8.6.5/src/mapogcapi.cpp
--- old/mapserver-8.6.3/src/mapogcapi.cpp       2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mapogcapi.cpp       2026-07-10 19:20:43.000000000 
+0200
@@ -1351,6 +1351,18 @@
       return MS_SUCCESS;
     }
   } else { // bbox query
+    const char *offsetStr = getRequestParameter(request, "offset");
+    if (offsetStr) {
+      if (msStringToInt(offsetStr, &offset, 10) != MS_SUCCESS) {
+        msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for offset.");
+        return MS_SUCCESS;
+      }
+      if (offset < 0) {
+        msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Offset out of range.");
+        return MS_SUCCESS;
+      }
+    }
+
     map->query.type = MS_QUERY_BY_RECT;
     map->query.mode = MS_QUERY_MULTIPLE;
     map->query.layer = i;
@@ -1376,14 +1388,8 @@
       map->query.only_cache_result_count = MS_FALSE;
       map->query.maxfeatures = limit;
 
-      const char *offsetStr = getRequestParameter(request, "offset");
       if (offsetStr) {
-        if (msStringToInt(offsetStr, &offset, 10) != MS_SUCCESS) {
-          msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Bad value for offset.");
-          return MS_SUCCESS;
-        }
-
-        if (offset < 0 || offset >= numberMatched) {
+        if (offset >= numberMatched) {
           msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Offset out of range.");
           return MS_SUCCESS;
         }
@@ -2023,9 +2029,6 @@
                    strstr(p, OGCAPI_MIMETYPE_HTML) != nullptr)) {
     format = OGCAPIFormat::HTML;
   } else if (p) {
-    std::string errorMsg("Unsupported format requested: ");
-    errorMsg += p;
-    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, errorMsg.c_str());
     format = OGCAPIFormat::Invalid;
   } else {
     format = OGCAPIFormat::HTML; // default for now
@@ -2060,6 +2063,7 @@
   const OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
 
   if (format == OGCAPIFormat::Invalid) {
+    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
     return MS_SUCCESS; // avoid any downstream MapServer processing
   }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapogcfilter.cpp 
new/mapserver-8.6.5/src/mapogcfilter.cpp
--- old/mapserver-8.6.3/src/mapogcfilter.cpp    2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mapogcfilter.cpp    2026-07-10 19:20:43.000000000 
+0200
@@ -806,6 +806,26 @@
   return status;
 }
 
+static bool msCheckDepthLessThanInternal(const CPLXMLNode *psNode,
+                                         int nMaxDepth) {
+  if (nMaxDepth <= 0)
+    return false;
+  for (const CPLXMLNode *psIter = psNode->psChild; psIter;
+       psIter = psIter->psNext) {
+    if (!msCheckDepthLessThanInternal(psIter, nMaxDepth - 1))
+      return false;
+  }
+  return true;
+}
+
+bool msCheckDepthLessThan(const CPLXMLNode *psNode, int nMaxDepth) {
+  for (const CPLXMLNode *psIter = psNode; psIter; psIter = psIter->psNext) {
+    if (!msCheckDepthLessThanInternal(psIter, nMaxDepth))
+      return false;
+  }
+  return true;
+}
+
 /************************************************************************/
 /*            FilterNode *FLTPaserFilterEncoding(char *szXMLString)     */
 /*                                                                      */
@@ -828,6 +848,11 @@
 
   if (psRoot == NULL)
     return NULL;
+  if (!msCheckDepthLessThan(psRoot, 256)) {
+    msDebug("FLTParseFilterEncoding(): %s", "Too deep nesting in filter");
+    CPLDestroyXMLNode(psRoot);
+    return NULL;
+  }
 
   /* strip namespaces. We srtip all name spaces (#1350)*/
   CPLStripXMLNamespace(psRoot, NULL, 1);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapogcfilter.h 
new/mapserver-8.6.5/src/mapogcfilter.h
--- old/mapserver-8.6.3/src/mapogcfilter.h      2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mapogcfilter.h      2026-07-10 19:20:43.000000000 
+0200
@@ -54,6 +54,9 @@
 /* -------------------------------------------------------------------- */
 /*      prototypes.                                                     */
 /* -------------------------------------------------------------------- */
+
+bool msCheckDepthLessThan(const CPLXMLNode *psNode, int nMaxDepth);
+
 MS_DLL_EXPORT int FLTIsNumeric(const char *pszValue);
 MS_DLL_EXPORT int FLTApplyExpressionToLayer(layerObj *lp,
                                             const char *pszExpression);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapogcsld.cpp 
new/mapserver-8.6.5/src/mapogcsld.cpp
--- old/mapserver-8.6.3/src/mapogcsld.cpp       2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mapogcsld.cpp       2026-07-10 19:20:43.000000000 
+0200
@@ -644,6 +644,11 @@
     msSetError(MS_WMSERR, "Invalid SLD document : %s", "", psSLDXML);
     return NULL;
   }
+  if (!msCheckDepthLessThan(psRoot, 256)) {
+    msSetError(MS_WMSERR, "Invalid SLD document : too deep nesting", "");
+    CPLDestroyXMLNode(psRoot);
+    return NULL;
+  }
 
   /* strip namespaces ogc and sld and gml */
   CPLStripXMLNamespace(psRoot, "ogc", 1);
@@ -4981,9 +4986,11 @@
     iValue = 0;
     for (int i = 0; i < nLength; i++) {
       // Check for comparison operator
-      if ((i + 1 < nLength && EQUALN(&pszExpression[i], szCompare, 2)) ||
-          (i + 1 < nLength && EQUALN(&pszExpression[i], szCompare2, 2)) ||
-          (i + 1 < nLength && EQUALN(&pszExpression[i], szCompare3, 2))) {
+      if ((i + 1 < nLength && EQUALN(&pszExpression[i], szCompare2, 2)) ||
+          (i + 1 < nLength && EQUALN(&pszExpression[i], szCompare3, 2)) ||
+          (i + 1 < nLength && EQUALN(&pszExpression[i], szCompare, 2) &&
+           (i == 0 || pszExpression[i - 1] == ' ') &&
+           (i + 2 >= nLength || pszExpression[i + 2] == ' '))) {
         // Extract value after the operator
         int offset = 2; // All operators are 2 characters long
         pszAttributeValue = msStrdup(&pszExpression[i + offset]);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapows.c 
new/mapserver-8.6.5/src/mapows.c
--- old/mapserver-8.6.3/src/mapows.c    2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/mapows.c    2026-07-10 19:20:43.000000000 +0200
@@ -1468,7 +1468,7 @@
   schemas_location =
       msLookupHashTable(&(map->web.metadata), "inspire_schemas_location");
   if (schemas_location == NULL)
-    schemas_location = "http://inspire.ec.europa.eu/schemas";;
+    schemas_location = INSPIRE_DEFAULT_SCHEMAS_LOCATION;
 
   return schemas_location;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapows.h 
new/mapserver-8.6.5/src/mapows.h
--- old/mapserver-8.6.3/src/mapows.h    2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/mapows.h    2026-07-10 19:20:43.000000000 +0200
@@ -40,6 +40,13 @@
  */
 #define OWS_DEFAULT_SCHEMAS_LOCATION "http://schemas.opengis.net";
 
+/* Likewise, this is the URL to the official INSPIRE Schema Repository. Used by
+ * default for INSPIRE services (i.e. services that define
+ * ows_inspire_capabilities) unless the inspire_schemas_location web
+ * metadata is set in the mapfile.
+ */
+#define INSPIRE_DEFAULT_SCHEMAS_LOCATION "https://inspire.ec.europa.eu/schemas";
+
 #if defined USE_LIBXML2 && defined USE_WFS_SVR
 #include <libxml/tree.h>
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mappostgis.cpp 
new/mapserver-8.6.5/src/mappostgis.cpp
--- old/mapserver-8.6.3/src/mappostgis.cpp      2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mappostgis.cpp      2026-07-10 19:20:43.000000000 
+0200
@@ -2024,18 +2024,16 @@
       }
     }
   }
-  bool insert_and = false;
+
   std::string strWhere;
   if (bIsValidRect && !strRect.empty()) {
     strWhere += strRect;
-    insert_and = true;
   }
 
   /* Handle a translated filter (RFC91). */
   if (layer->filter.native_string) {
-    if (insert_and) {
+    if (!strWhere.empty()) {
       strWhere += " AND ";
-      insert_and = true;
     }
     strWhere += '(';
     strWhere += layer->filter.native_string;
@@ -2045,17 +2043,17 @@
   /* Handle a native filter set as a PROCESSING option (#5001). */
   const char *native_filter = msLayerGetProcessingKey(layer, "NATIVE_FILTER");
   if (native_filter) {
-    if (insert_and) {
+    if (!strWhere.empty()) {
       strWhere += " AND ";
-      insert_and = true;
     }
+
     strWhere += '(';
     strWhere += native_filter;
     strWhere += ')';
   }
 
   if (uid) {
-    if (insert_and) {
+    if (!strWhere.empty()) {
       strWhere += " AND ";
     }
 
@@ -3736,6 +3734,17 @@
       native_string += stresc;
       native_string += '\'';
     } else {
+      char *endptr = nullptr;
+      std::strtod(stresc, &endptr);
+      if (endptr != stresc + strlen(stresc)) {
+        if (layer->debug >= 2) {
+          msDebug(
+              "msPostGISLayerTranslateFilter. '%s' is not a numeric value.\n",
+              filter->string);
+        }
+        msFree(stresc);
+        return MS_FAILURE;
+      }
       native_string += stresc;
     }
     msFree(stresc);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mappostgresql.c 
new/mapserver-8.6.5/src/mappostgresql.c
--- old/mapserver-8.6.3/src/mappostgresql.c     2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mappostgresql.c     2026-07-10 19:20:43.000000000 
+0200
@@ -266,6 +266,19 @@
   return MS_SUCCESS;
 }
 
+static char *msPOSTGRESQLEscapeSQLParam(PGconn *conn, const char *pszString) {
+
+  size_t nSrcLen = strlen(pszString);
+  char *pszEscapedStr = (char *)msSmallMalloc(2 * nSrcLen + 1);
+  int nError = 0;
+  PQescapeStringConn(conn, pszEscapedStr, pszString, nSrcLen, &nError);
+  if (nError != 0) {
+    free(pszEscapedStr);
+    pszEscapedStr = NULL;
+  }
+  return pszEscapedStr;
+}
+
 /************************************************************************/
 /*                       msPOSTGRESQLJoinNext()                         */
 /*                                                                      */
@@ -306,7 +319,8 @@
     /* Write the list of column names. */
     length = 0;
     for (i = 0; i < join->numitems; i++) {
-      length += 8 + strlen(join->items[i]) + 2;
+      length += strlen("::text") + strlen("\"\"") + strlen(join->items[i]) * 2 
+
+                strlen(", ");
     }
     if (length > 1024 * 1024) {
       msSetError(MS_MEMERR, "Too many joins.\n", "msPOSTGRESQLJoinNext()");
@@ -321,24 +335,33 @@
 
     columns[0] = 0;
     for (i = 0; i < join->numitems; i++) {
-      strcat(columns, "\"");
-      strcat(columns, join->items[i]);
-      strcat(columns, "\"::text");
+      char *stresc = msDefaultEscapePropertyName(join->items[i]);
+      strcat(columns, stresc);
+      msFree(stresc);
+      strcat(columns, "::text");
       if (i != join->numitems - 1) {
         strcat(columns, ", ");
       }
     }
 
     /* Create the query string. */
-    const size_t nSize = 26 + strlen(columns) + strlen(join->table) +
-                         strlen(join->to) + strlen(joininfo->from_value);
-    sql = (char *)malloc(nSize);
-    if (!sql) {
-      msSetError(MS_MEMERR, "Failure to malloc.\n", "msPOSTGRESQLJoinNext()");
+    char *pszEscapedFrom =
+        msPOSTGRESQLEscapeSQLParam(joininfo->conn, joininfo->from_value);
+    if (!pszEscapedFrom) {
+      free(columns);
       return MS_FAILURE;
     }
+    char *pszEscapedTable = msDefaultEscapePropertyName(join->table);
+    char *pszEscapedTo = msDefaultEscapePropertyName(join->to);
+    const size_t nSize = strlen("SELECT  FROM  WHERE  = ''") + strlen(columns) 
+
+                         strlen(pszEscapedTable) + strlen(pszEscapedTo) +
+                         strlen(pszEscapedFrom) + 1;
+    sql = (char *)msSmallMalloc(nSize);
     snprintf(sql, nSize, "SELECT %s FROM %s WHERE %s = '%s'", columns,
-             join->table, join->to, joininfo->from_value);
+             pszEscapedTable, pszEscapedTo, pszEscapedFrom);
+    msFree(pszEscapedTable);
+    msFree(pszEscapedTo);
+    msFree(pszEscapedFrom);
     if (joininfo->layer_debug) {
       msDebug("msPOSTGRESQLJoinNext(): executing %s.\n", sql);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/maprasterquery.c 
new/mapserver-8.6.5/src/maprasterquery.c
--- old/mapserver-8.6.3/src/maprasterquery.c    2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/maprasterquery.c    2026-07-10 19:20:43.000000000 
+0200
@@ -1205,7 +1205,10 @@
 
         switch (rlinfo->eDataType) {
         case GDT_Byte:
+#if GDAL_VERSION_MAJOR > 3 ||                                                  
\
+    (GDAL_VERSION_MAJOR == 3 && GDAL_VERSION_MINOR >= 7)
         case GDT_Int8:
+#endif
         case GDT_UInt16:
         case GDT_Int16:
         case GDT_Int32:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapscale.c 
new/mapserver-8.6.5/src/mapscale.c
--- old/mapserver-8.6.3/src/mapscale.c  2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/mapscale.c  2026-07-10 19:20:43.000000000 +0200
@@ -309,7 +309,7 @@
         }
       }
 
-      sprintf(label, "%g", j * i);
+      snprintf(label, sizeof(label), "%g", j * i);
       map->scalebar.label.position = MS_CC;
       p.x = ox + j * isx; /* + MS_NINT(fontPtr->w/2); */
       p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
@@ -320,9 +320,10 @@
       }
       state = -state;
     }
-    sprintf(label, "%g", j * i);
+    snprintf(label, sizeof(label), "%g", j * i);
     ox = ox + j * isx - MS_NINT((strlen(label) * fontWidth) / 2.0);
-    sprintf(label, "%g %s", j * i, unitText[map->scalebar.units]);
+    snprintf(label, sizeof(label), "%g %s", j * i,
+             unitText[map->scalebar.units]);
     map->scalebar.label.position = MS_CR;
     p.x = ox; /* + MS_NINT(fontPtr->w/2); */
     p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
@@ -361,12 +362,13 @@
         goto scale_cleanup;
       }
 
-      sprintf(label, "%g", j * i);
+      snprintf(label, sizeof(label), "%g", j * i);
       if (j != map->scalebar.intervals) {
         map->scalebar.label.position = MS_CC;
         p.x = ox + j * isx; /* + MS_NINT(fontPtr->w/2); */
       } else {
-        sprintf(label, "%g %s", j * i, unitText[map->scalebar.units]);
+        snprintf(label, sizeof(label), "%g %s", j * i,
+                 unitText[map->scalebar.units]);
         map->scalebar.label.position = MS_CR;
         p.x = ox + j * isx - MS_NINT((strlen(label) * fontWidth) / 2.0);
       }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapscript/python/pyextend.i 
new/mapserver-8.6.5/src/mapscript/python/pyextend.i
--- old/mapserver-8.6.3/src/mapscript/python/pyextend.i 2026-05-07 
14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/mapscript/python/pyextend.i 2026-07-10 
19:20:43.000000000 +0200
@@ -257,7 +257,7 @@
         PyObject *order;
         order = PyTuple_New(self->numlayers);
         for (i = 0; i < self->numlayers; i++) {
-            PyTuple_SetItem(order,i,PyInt_FromLong((long)self->layerorder[i]));
+            
PyTuple_SetItem(order,i,PyLong_FromLong((long)self->layerorder[i]));
         }
         return order;
     } 
@@ -269,7 +269,7 @@
         int i;
         Py_ssize_t size = PyTuple_Size(order);
         for (i = 0; i < size; i++) {
-            self->layerorder[i] = (int)PyInt_AsLong(PyTuple_GetItem(order, i));
+            self->layerorder[i] = (int)PyLong_AsLong(PyTuple_GetItem(order, 
i));
         }
         return MS_SUCCESS;
     }
@@ -281,8 +281,8 @@
     {
         PyObject* output ;
         output = PyTuple_New(2);
-        PyTuple_SetItem(output,0,PyInt_FromLong((long)self->width));
-        PyTuple_SetItem(output,1,PyInt_FromLong((long)self->height));
+        PyTuple_SetItem(output,0,PyLong_FromLong((long)self->width));
+        PyTuple_SetItem(output,1,PyLong_FromLong((long)self->height));
         return output;
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapserv-index.cpp 
new/mapserver-8.6.5/src/mapserv-index.cpp
--- old/mapserver-8.6.3/src/mapserv-index.cpp   2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mapserv-index.cpp   2026-07-10 19:20:43.000000000 
+0200
@@ -425,7 +425,7 @@
 int msOGCAPIDispatchMapIndexRequest(mapservObj *mapserv, configObj *config) {
 #ifdef USE_OGCAPI_SVR
   if (!mapserv || !config)
-    return -1; // Handle null pointers
+    return MS_FAILURE; // Handle null pointers
 
   cgiRequestObj *request = mapserv->request;
 
@@ -437,6 +437,12 @@
   }
 
   OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
+
+  if (format == OGCAPIFormat::Invalid) {
+    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+    return MS_FAILURE;
+  }
+
   const char *key = request->api_path[0];
 
   mapObj *map = getMapFromConfig(config, key);
@@ -479,11 +485,16 @@
 int msOGCAPIDispatchIndexRequest(mapservObj *mapserv, configObj *config) {
 #ifdef USE_OGCAPI_SVR
   if (!mapserv || !config)
-    return -1; // Handle null pointers
+    return MS_FAILURE; // Handle null pointers
 
   cgiRequestObj *request = mapserv->request;
   const OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
 
+  if (format == OGCAPIFormat::Invalid) {
+    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+    return MS_FAILURE;
+  }
+
   const char *key = NULL;
   json links = json::array();
 
@@ -504,7 +515,7 @@
   } else if (format == OGCAPIFormat::HTML) {
     createHTMLOutput(response, TEMPLATE_HTML_INDEX);
   } else {
-    msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+    assert(false && "Unhandled OGCAPIFormat value");
   }
 
   return MS_SUCCESS;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapserver.h 
new/mapserver-8.6.5/src/mapserver.h
--- old/mapserver-8.6.3/src/mapserver.h 2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/mapserver.h 2026-07-10 19:20:43.000000000 +0200
@@ -2889,7 +2889,9 @@
 MS_DLL_EXPORT int msEncodeChar(const char);
 MS_DLL_EXPORT char *msEncodeUrlExcept(const char *, const char);
 MS_DLL_EXPORT char *msEncodeUrl(const char *);
-MS_DLL_EXPORT char *msEscapeJSonString(const char *pszJSonString);
+char *msDefaultEscapePropertyName(const char *pszString);
+MS_DLL_EXPORT char *msEscapeJSonString(const char *pszString);
+MS_DLL_EXPORT char *msEscapeJSonLikeString(const char *pszString, char 
chQuote);
 MS_DLL_EXPORT char *msEncodeHTMLEntities(const char *string);
 MS_DLL_EXPORT void msDecodeHTMLEntities(const char *string);
 MS_DLL_EXPORT int msIsXMLTagValid(const char *string);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapstring.cpp 
new/mapserver-8.6.5/src/mapstring.cpp
--- old/mapserver-8.6.3/src/mapstring.cpp       2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/mapstring.cpp       2026-07-10 19:20:43.000000000 
+0200
@@ -1205,18 +1205,18 @@
 /*                            msEscapeJSonString()                      */
 /************************************************************************/
 
-/* The input (and output) string are not supposed to start/end with double */
-/* quote characters. It is the responsibility of the caller to do that. */
-char *msEscapeJSonString(const char *pszJSonString) {
+/* The input (and output) string are not supposed to start/end with chQuote
+ * characters. It is the responsibility of the caller to do that. */
+char *msEscapeJSonLikeString(const char *pszString, char chQuote) {
   /* Worst case is one character to become \uABCD so 6 characters */
   char *pszRet;
   int i = 0, j = 0;
   static const char *pszHex = "0123456789ABCDEF";
 
-  pszRet = (char *)msSmallMalloc(strlen(pszJSonString) * 6 + 1);
+  pszRet = (char *)msSmallMalloc(strlen(pszString) * 6 + 1);
   /* From http://www.json.org/ */
-  for (i = 0; pszJSonString[i] != '\0'; i++) {
-    unsigned char ch = pszJSonString[i];
+  for (i = 0; pszString[i] != '\0'; i++) {
+    unsigned char ch = pszString[i];
     if (ch == '\b') {
       pszRet[j++] = '\\';
       pszRet[j++] = 'b';
@@ -1239,9 +1239,9 @@
       pszRet[j++] = '0';
       pszRet[j++] = pszHex[ch / 16];
       pszRet[j++] = pszHex[ch % 16];
-    } else if (ch == '"') {
+    } else if (ch == chQuote) {
       pszRet[j++] = '\\';
-      pszRet[j++] = '"';
+      pszRet[j++] = chQuote;
     } else if (ch == '\\') {
       pszRet[j++] = '\\';
       pszRet[j++] = '\\';
@@ -1253,6 +1253,12 @@
   return pszRet;
 }
 
+/* The input (and output) string are not supposed to start/end with double
+ * quote characters. It is the responsibility of the caller to do that. */
+char *msEscapeJSonString(const char *pszString) {
+  return msEscapeJSonLikeString(pszString, '"');
+}
+
 /* msEncodeHTMLEntities()
 **
 ** Return a copy of string after replacing some problematic chars with their
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/maptemplate.c 
new/mapserver-8.6.5/src/maptemplate.c
--- old/mapserver-8.6.3/src/maptemplate.c       2026-05-07 14:17:41.000000000 
+0200
+++ new/mapserver-8.6.5/src/maptemplate.c       2026-07-10 19:20:43.000000000 
+0200
@@ -43,6 +43,7 @@
 
 #include <assert.h>
 #include <ctype.h>
+#include <math.h>
 
 static inline void IGUR_sizet(size_t ignored) {
   (void)ignored;
@@ -82,11 +83,19 @@
     "    <script "
     "src=\"[openlayers_js_url]\"></script>\n"
     "    <script>\n"
+    "        if (!ol.proj.get('[openlayers_projection]')) {\n"
+    "            ol.proj.addProjection(new ol.proj.Projection({ code: "
+    "'[openlayers_projection]' }));\n"
+    "        }\n"
     "        [openlayers_layer]\n"
     "        const map = new ol.Map({\n"
     "            layers: [mslayer],\n"
     "            target: 'map',\n"
-    "            view: new ol.View()\n"
+    "            view: new ol.View({\n"
+    "                projection: '[openlayers_projection]',\n"
+    "                minResolution: [ol_minresolution],\n"
+    "                maxResolution: [ol_maxresolution]\n"
+    "            })\n"
     "        });\n"
     "        map.getView().fit([[minx], [miny], [maxx], [maxy]], { size: "
     "map.getSize() });\n"
@@ -108,11 +117,7 @@
     "        });";
 
 static const char *const olLayerWMSTag =
-    "if (!ol.proj.get('[openlayers_projection]')) {\n"
-    "            ol.proj.addProjection(new ol.proj.Projection({ code : "
-    "'[openlayers_projection]' }));\n"
-    "        }\n"
-    "        const mslayer = new ol.layer.Image({\n"
+    "const mslayer = new ol.layer.Image({\n"
     "            source: new ol.source.Image({\n"
     "                loader: ol.source.wms.createLoader({\n"
     "                    url: '[mapserv_onlineresource]',\n"
@@ -4097,7 +4102,27 @@
 #else
     ol = msBuildOnlineResource(mapserv->map, mapserv->request);
 #endif
-    outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]", ol);
+
+    if (strstr(outstr, "'[mapserv_onlineresource]'")) {
+      // Fix
+      // 
https://github.com/MapServer/MapServer/security/advisories/GHSA-xqj6-vjqr-33vv
+      // The value is inside a single-quoted JS string in a <script> element.
+      // Escaping the quote is not enough: a literal "</script>" in the value
+      // still closes the element. Encode '<' and '>' as JS unicode escapes so
+      // they cannot break out of the script block.
+      char *pszEscaped = msEscapeJSonLikeString(ol, '\'');
+      pszEscaped = msReplaceSubstring(pszEscaped, "<", "\\u003c");
+      pszEscaped = msReplaceSubstring(pszEscaped, ">", "\\u003e");
+      const size_t nLen = 1 + strlen(pszEscaped) + 1 + 1;
+      char *pszEscapedWithSingleQuotes = (char *)msSmallMalloc(nLen);
+      snprintf(pszEscapedWithSingleQuotes, nLen, "'%s'", pszEscaped);
+      outstr = msReplaceSubstring(outstr, "'[mapserv_onlineresource]'",
+                                  pszEscapedWithSingleQuotes);
+      msFree(pszEscapedWithSingleQuotes);
+      msFree(pszEscaped);
+    } else {
+      outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]", ol);
+    }
     msFree(ol);
   }
 
@@ -5031,6 +5056,16 @@
     }
   }
 
+  if (mapserv->Mode == BROWSE) {
+    char *epsgCode = NULL;
+    msOWSGetEPSGProj(&(mapserv->map->projection), NULL, NULL, MS_TRUE,
+                     &epsgCode);
+    if (epsgCode) {
+      // Transfers ownership of epsgCode to projection
+      projection = epsgCode;
+    }
+  }
+
   if (mapserv->map->outputformat->mimetype &&
       *mapserv->map->outputformat->mimetype) {
     format = mapserv->map->outputformat->mimetype;
@@ -5061,12 +5096,36 @@
   buffer = msReplaceSubstring(buffer, "[openlayers_js_url]", openlayersUrl);
   buffer = msReplaceSubstring(buffer, "[openlayers_css_url]", 
openlayersCssUrl);
   buffer = msReplaceSubstring(buffer, "[openlayers_layer]", layer);
-  if (projection)
-    buffer = msReplaceSubstring(buffer, "[openlayers_projection]", projection);
-  if (format)
+  if (!projection) {
+    // if no projection can be found then use the default OL projection
+    projection = msStrdup("EPSG:3857");
+  }
+  buffer = msReplaceSubstring(buffer, "[openlayers_projection]", projection);
+  if (format) {
     buffer = msReplaceSubstring(buffer, "[openlayers_format]", format);
-  else
+  } else {
     buffer = msReplaceSubstring(buffer, "[openlayers_format]", "image/png");
+  }
+
+  double extentWidth = mapserv->map->extent.maxx - mapserv->map->extent.minx;
+  double extentHeight = mapserv->map->extent.maxy - mapserv->map->extent.miny;
+  // assume default tile size and zoom-levels
+  int zoomLevels = 20;
+  double maxResolution = MS_MAX(extentWidth, extentHeight) / 256.0;
+
+  if (maxResolution <= 0) {
+    maxResolution = 1; // fallback to avoid any divide by zero
+  }
+
+  double minResolution = maxResolution / pow(2.0, zoomLevels);
+  char olMinRes[64], olMaxRes[64];
+
+  snprintf(olMaxRes, sizeof(olMaxRes), "%g", maxResolution);
+  snprintf(olMinRes, sizeof(olMinRes), "%g", minResolution);
+
+  buffer = msReplaceSubstring(buffer, "[ol_maxresolution]", olMaxRes);
+  buffer = msReplaceSubstring(buffer, "[ol_minresolution]", olMinRes);
+
   msIO_fwrite(buffer, strlen(buffer), 1, stdout);
   free(layer);
   free(buffer);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/maptree.c 
new/mapserver-8.6.5/src/maptree.c
--- old/mapserver-8.6.3/src/maptree.c   2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/maptree.c   2026-07-10 19:20:43.000000000 +0200
@@ -380,7 +380,7 @@
   return (treeNodeAddShapeId(tree->root, id, rect, tree->maxdepth));
 }
 
-static void treeCollectShapeIds(treeNodeObj *node, rectObj aoi,
+static void treeCollectShapeIds(treeNodeObj *node, rectObj aoi, int numshapes,
                                 ms_bitarray status) {
   int i;
 
@@ -395,14 +395,15 @@
   /*      Add the local nodes shapeids to the list.                       */
   /* -------------------------------------------------------------------- */
   for (i = 0; i < node->numshapes; i++)
-    msSetBit(status, node->ids[i], 1);
+    if (node->ids[i] >= 0 && node->ids[i] < numshapes)
+      msSetBit(status, node->ids[i], 1);
 
   /* -------------------------------------------------------------------- */
   /*      Recurse to subnodes if they exist.                              */
   /* -------------------------------------------------------------------- */
   for (i = 0; i < node->numsubnodes; i++) {
     if (node->subnode[i])
-      treeCollectShapeIds(node->subnode[i], aoi, status);
+      treeCollectShapeIds(node->subnode[i], aoi, numshapes, status);
   }
 }
 
@@ -415,7 +416,7 @@
     return (NULL);
   }
 
-  treeCollectShapeIds(tree->root, aoi, status);
+  treeCollectShapeIds(tree->root, aoi, tree->numshapes, status);
 
   return (status);
 }
@@ -507,11 +508,13 @@
     if (disktree->needswap) {
       for (i = 0; i < numshapes; i++) {
         SwapWord(4, &ids[i]);
-        msSetBit(status, ids[i], 1);
+        if (ids[i] >= 0 && ids[i] < disktree->nShapes)
+          msSetBit(status, ids[i], 1);
       }
     } else {
       for (i = 0; i < numshapes; i++)
-        msSetBit(status, ids[i], 1);
+        if (ids[i] >= 0 && ids[i] < disktree->nShapes)
+          msSetBit(status, ids[i], 1);
     }
     free(ids);
     ids = NULL;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapwcs.cpp 
new/mapserver-8.6.5/src/mapwcs.cpp
--- old/mapserver-8.6.3/src/mapwcs.cpp  2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/mapwcs.cpp  2026-07-10 19:20:43.000000000 +0200
@@ -357,6 +357,23 @@
 }
 
 /************************************************************************/
+/*                             msWCSSetParam                            */
+/************************************************************************/
+
+static int msWCSSetParam(char **ppszOut, cgiRequestObj *request, int i,
+                         const char *pszExpectedParamName) {
+  if (strcasecmp(request->ParamNames[i], pszExpectedParamName) == 0) {
+    /* Keep the first value supplied and ignore later duplicates. This avoids
+       leaking the previously allocated value when the same parameter appears
+       multiple times in a request (consistent with msWFSSetParam()). */
+    if (*ppszOut == NULL)
+      *ppszOut = msStrdup(request->ParamValues[i]);
+    return 1;
+  }
+  return 0;
+}
+
+/************************************************************************/
 /*                         msWCSParseRequest()                          */
 /************************************************************************/
 
@@ -434,6 +451,15 @@
           if (EQUAL((char *)tmpNode->name, "BoundingBox")) {
             xmlNodePtr cornerNode = NULL;
             params->crs = (char *)xmlGetProp(tmpNode, BAD_CAST "crs");
+            if (!params->crs) {
+              msSetError(MS_WCSERR, "Required parameter CRS was not supplied.",
+                         "msWCSGetCoverage()");
+              msWCSException(map, "MissingParameterValue", "crs",
+                             params->version);
+              xmlFreeDoc(doc);
+              xmlCleanupParser();
+              return MS_DONE;
+            }
             if (strncasecmp(params->crs, "urn:ogc:def:crs:", 16) == 0 &&
                 strncasecmp(params->crs + strlen(params->crs) - 8, "imageCRS",
                             8) == 0)
@@ -447,8 +473,13 @@
                   msSetError(MS_WCSERR,
                              "Wrong number of arguments for LowerCorner",
                              "msWCSParseRequest()");
-                  return msWCSException(map, "InvalidParameterValue",
-                                        "LowerCorner", params->version);
+                  msWCSException(map, "InvalidParameterValue", "LowerCorner",
+                                 params->version);
+                  msFreeCharArray(tokens, n);
+                  xmlFree(value);
+                  xmlFreeDoc(doc);
+                  xmlCleanupParser();
+                  return MS_DONE;
                 }
                 params->bbox.minx = atof(tokens[0]);
                 params->bbox.miny = atof(tokens[1]);
@@ -462,8 +493,13 @@
                   msSetError(MS_WCSERR,
                              "Wrong number of arguments for UpperCorner",
                              "msWCSParseRequest()");
-                  return msWCSException(map, "InvalidParameterValue",
-                                        "UpperCorner", params->version);
+                  msWCSException(map, "InvalidParameterValue", "UpperCorner",
+                                 params->version);
+                  msFreeCharArray(tokens, n);
+                  xmlFree(value);
+                  xmlFreeDoc(doc);
+                  xmlCleanupParser();
+                  return MS_DONE;
                 }
                 params->bbox.maxx = atof(tokens[0]);
                 params->bbox.maxy = atof(tokens[1]);
@@ -493,8 +529,13 @@
                   msSetError(MS_WCSERR,
                              "Wrong number of arguments for GridOrigin",
                              "msWCSParseRequest()");
-                  return msWCSException(map, "InvalidParameterValue",
-                                        "GridOffsets", params->version);
+                  msWCSException(map, "InvalidParameterValue", "GridOffsets",
+                                 params->version);
+                  msFreeCharArray(tokens, n);
+                  xmlFree(value);
+                  xmlFreeDoc(doc);
+                  xmlCleanupParser();
+                  return MS_DONE;
                 }
                 params->originx = atof(tokens[0]);
                 params->originy = atof(tokens[1]);
@@ -507,8 +548,13 @@
                   msSetError(MS_WCSERR,
                              "Wrong number of arguments for GridOffsets",
                              "msWCSParseRequest()");
-                  return msWCSException(map, "InvalidParameterValue",
-                                        "GridOffsets", params->version);
+                  msWCSException(map, "InvalidParameterValue", "GridOffsets",
+                                 params->version);
+                  msFreeCharArray(tokens, n);
+                  xmlFree(value);
+                  xmlFreeDoc(doc);
+                  xmlCleanupParser();
+                  return MS_DONE;
                 }
                 /* take absolute values to convert to positive RESX/RESY style
                 WCS 1.0 behavior.  *but* this does break some possibilities! */
@@ -540,22 +586,20 @@
   if (request->NumParams > 0) {
     for (i = 0; i < request->NumParams; i++) {
 
-      if (strcasecmp(request->ParamNames[i], "VERSION") == 0)
-        params->version = msStrdup(request->ParamValues[i]);
-      if (strcasecmp(request->ParamNames[i], "UPDATESEQUENCE") == 0)
-        params->updatesequence = msStrdup(request->ParamValues[i]);
-      else if (strcasecmp(request->ParamNames[i], "REQUEST") == 0)
-        params->request = msStrdup(request->ParamValues[i]);
-      else if (strcasecmp(request->ParamNames[i], "INTERPOLATION") == 0)
-        params->interpolation = msStrdup(request->ParamValues[i]);
-      else if (strcasecmp(request->ParamNames[i], "SERVICE") == 0)
-        params->service = msStrdup(request->ParamValues[i]);
-      else if (strcasecmp(request->ParamNames[i], "SECTION") == 0) /* 1.0 */
-        params->section =
-            msStrdup(request->ParamValues[i]); /* TODO: validate value here */
-      else if (strcasecmp(request->ParamNames[i], "SECTIONS") == 0) /* 1.1 */
-        params->section =
-            msStrdup(request->ParamValues[i]); /* TODO: validate value here */
+      if (msWCSSetParam(&(params->version), request, i, "VERSION")) {
+      } else if (msWCSSetParam(&(params->updatesequence), request, i,
+                               "UPDATESEQUENCE")) {
+      } else if (msWCSSetParam(&(params->request), request, i, "REQUEST")) {
+      } else if (msWCSSetParam(&(params->interpolation), request, i,
+                               "INTERPOLATION")) {
+      } else if (msWCSSetParam(&(params->service), request, i, "SERVICE")) {
+      } else if (msWCSSetParam(&(params->section), request, i,
+                               "SECTION")) { /* 1.0 */
+        /* TODO: validate value here */
+      } else if (msWCSSetParam(&(params->section), request, i,
+                               "SECTIONS")) { /* 1.1 */
+        /* TODO: validate value here */
+      }
 
       /* GetCoverage parameters. */
       else if (strcasecmp(request->ParamNames[i], "BBOX") == 0) {
@@ -583,14 +627,12 @@
       else if (strcasecmp(request->ParamNames[i], "COVERAGE") == 0)
         params->coverages =
             CSLAddString(params->coverages, request->ParamValues[i]);
-      else if (strcasecmp(request->ParamNames[i], "TIME") == 0)
-        params->time = msStrdup(request->ParamValues[i]);
-      else if (strcasecmp(request->ParamNames[i], "FORMAT") == 0)
-        params->format = msStrdup(request->ParamValues[i]);
-      else if (strcasecmp(request->ParamNames[i], "CRS") == 0)
-        params->crs = msStrdup(request->ParamValues[i]);
-      else if (strcasecmp(request->ParamNames[i], "RESPONSE_CRS") == 0)
-        params->response_crs = msStrdup(request->ParamValues[i]);
+      else if (msWCSSetParam(&(params->time), request, i, "TIME")) {
+      } else if (msWCSSetParam(&(params->format), request, i, "FORMAT")) {
+      } else if (msWCSSetParam(&(params->crs), request, i, "CRS")) {
+      } else if (msWCSSetParam(&(params->response_crs), request, i,
+                               "RESPONSE_CRS")) {
+      }
 
       /* WCS 1.1 DescribeCoverage and GetCoverage ... */
       else if (strcasecmp(request->ParamNames[i], "IDENTIFIER") == 0 ||
@@ -606,8 +648,10 @@
         if (tokens == NULL || n < 5) {
           msSetError(MS_WCSERR, "Wrong number of arguments for BOUNDINGBOX.",
                      "msWCSParseRequest()");
-          return msWCSException(map, "InvalidParameterValue", "boundingbox",
-                                params->version);
+          msWCSException(map, "InvalidParameterValue", "boundingbox",
+                         params->version);
+          msFreeCharArray(tokens, n);
+          return MS_DONE;
         }
 
         /* NOTE: WCS 1.1 boundingbox is center of pixel oriented, not edge
@@ -618,6 +662,7 @@
         params->bbox.maxx = atof(tokens[2]);
         params->bbox.maxy = atof(tokens[3]);
 
+        msFree(params->crs);
         params->crs = msStrdup(tokens[4]);
         msFreeCharArray(tokens, n);
         /* normalize imageCRS urns to simply "imageCRS" */
@@ -630,8 +675,10 @@
         if (tokens == NULL || n < 2) {
           msSetError(MS_WCSERR, "Wrong number of arguments for GridOffsets",
                      "msWCSParseRequest()");
-          return msWCSException(map, "InvalidParameterValue", "GridOffsets",
-                                params->version);
+          msWCSException(map, "InvalidParameterValue", "GridOffsets",
+                         params->version);
+          msFreeCharArray(tokens, n);
+          return MS_DONE;
         }
         /* take absolute values to convert to positive RESX/RESY style
            WCS 1.0 behavior.  *but* this does break some possibilities! */
@@ -643,8 +690,10 @@
         if (tokens == NULL || n < 2) {
           msSetError(MS_WCSERR, "Wrong number of arguments for GridOrigin",
                      "msWCSParseRequest()");
-          return msWCSException(map, "InvalidParameterValue", "GridOffsets",
-                                params->version);
+          msWCSException(map, "InvalidParameterValue", "GridOffsets",
+                         params->version);
+          msFreeCharArray(tokens, n);
+          return MS_DONE;
         }
         params->originx = atof(tokens[0]);
         params->originy = atof(tokens[1]);
@@ -3163,6 +3212,11 @@
       strcmp(ows_request->version, "1.1.2") == 0) {
     auto paramsTmp = msWCSCreateParams();
     status = msWCSParseRequest(request, paramsTmp, map);
+    if (status == MS_DONE) {
+      msWCSFreeParams(paramsTmp);
+      free(paramsTmp);
+      return MS_FAILURE;
+    }
     if (status == MS_FAILURE) {
       msWCSFreeParams(paramsTmp);
       free(paramsTmp);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mapserver-8.6.3/src/mapwms.cpp 
new/mapserver-8.6.5/src/mapwms.cpp
--- old/mapserver-8.6.3/src/mapwms.cpp  2026-05-07 14:17:41.000000000 +0200
+++ new/mapserver-8.6.5/src/mapwms.cpp  2026-07-10 19:20:43.000000000 +0200
@@ -991,9 +991,12 @@
     non mandatory
    */
   for (int i = 0; i < numentries; i++) {
+    if (strcasecmp(names[i], "REQUEST") == 0) {
+      request = values[i];
+    }
     /* check if SLD is passed.  If yes, check for OGR support */
-    if (strcasecmp(names[i], "SLD") == 0 ||
-        strcasecmp(names[i], "SLD_BODY") == 0) {
+    else if (strcasecmp(names[i], "SLD") == 0 ||
+             strcasecmp(names[i], "SLD_BODY") == 0) {
       sldenabled =
           msOWSLookupMetadata(&(map->web.metadata), "MO", "sld_enabled");
 
@@ -1012,15 +1015,15 @@
     }
   }
 
+  const char *layerKey = request && strcasecmp(request, "GetLegendGraphic") == 0
+                             ? "LAYER"
+                             : "LAYERS";
+
   std::vector<std::string> wmslayers;
   for (int i = 0; i < numentries; i++) {
     /* getMap parameters */
 
-    if (strcasecmp(names[i], "REQUEST") == 0) {
-      request = values[i];
-    }
-
-    if (strcasecmp(names[i], "LAYERS") == 0) {
+    if (strcasecmp(names[i], layerKey) == 0) {
       std::vector<int> layerOrder(map->numlayers);
 
       wmslayers = msStringSplit(values[i], ',');
@@ -5983,16 +5986,6 @@
     }
     if (found) {
       isContentDependentLegend = true;
-      /* getLegendGraphic uses LAYER= , we need to create a LAYERS= value that
-       * is identical we'll suppose that the client is conformat and hasn't
-       * included a LAYERS= parameter in its request */
-      for (int i = 0; i < req->NumParams; i++) {
-        if (strcasecmp(req->ParamNames[i], "LAYER") == 0) {
-          req->ParamNames[req->NumParams] = msStrdup("LAYERS");
-          req->ParamValues[req->NumParams] = msStrdup(req->ParamValues[i]);
-          req->NumParams++;
-        }
-      }
     } else {
       return msWMSLegendGraphic(map, nVersion, req->ParamNames,
                                 req->ParamValues, req->NumParams,

Reply via email to