diff -ru dnsdist-2.0.2.orig/dnsdist-configuration.hh dnsdist-2.0.2/dnsdist-configuration.hh
--- dnsdist-2.0.2.orig/dnsdist-configuration.hh	2025-11-27 14:25:28.000000000 +0100
+++ dnsdist-2.0.2/dnsdist-configuration.hh	2026-02-23 15:01:37.069368518 +0100
@@ -170,6 +170,7 @@
   bool d_logConsoleConnections{true};
   bool d_addEDNSToSelfGeneratedResponses{true};
   bool d_applyACLToProxiedClients{false};
+  bool d_webServerAllowCrossOriginRequests{false}; // Whether the webserver / API allows cross-origin requests
 };
 
 /* Be careful not to hold on this for too long, it can be invalidated
diff -ru dnsdist-2.0.2.orig/dnsdist-lua.cc dnsdist-2.0.2/dnsdist-lua.cc
--- dnsdist-2.0.2.orig/dnsdist-lua.cc	2025-11-27 14:25:28.000000000 +0100
+++ dnsdist-2.0.2/dnsdist-lua.cc	2026-02-23 15:01:37.070270769 +0100
@@ -1106,6 +1106,7 @@
       bool apiRequiresAuthentication{true};
       bool dashboardRequiresAuthentication{true};
       bool hashPlaintextCredentials = false;
+      bool allowCrossOriginRequests = false;
       getOptionalValue<bool>(vars, "hashPlaintextCredentials", hashPlaintextCredentials);
 
       if (getOptionalValue<std::string>(vars, "password", password) > 0) {
@@ -1145,6 +1146,10 @@
       if (getOptionalValue<bool>(vars, "dashboardRequiresAuthentication", dashboardRequiresAuthentication) > 0) {
         config.d_dashboardRequiresAuthentication = dashboardRequiresAuthentication;
       }
+
+      if (getOptionalValue<bool>(vars, "allowCrossOriginRequests", allowCrossOriginRequests) > 0) {
+        config.d_webServerAllowCrossOriginRequests = allowCrossOriginRequests;
+      }
     });
 
     int maxConcurrentConnections = 0;
diff -ru dnsdist-2.0.2.orig/dnsdist-settings-definitions.yml dnsdist-2.0.2/dnsdist-settings-definitions.yml
--- dnsdist-2.0.2.orig/dnsdist-settings-definitions.yml	2025-11-27 14:25:28.000000000 +0100
+++ dnsdist-2.0.2/dnsdist-settings-definitions.yml	2026-02-23 15:01:37.071684427 +0100
@@ -427,6 +427,10 @@
       type: "Vec<String>"
       default: "127.0.0.1, ::1"
       description: "List of network masks or IP addresses that are allowed to open a connection to the web server"
+    - name: "allow_cross_origin_requests"
+      type: "bool"
+      default: "false"
+      description: "Whether the webserver allows cross-origin HTTP requests. This might allow a malicious website to read metrics provided by the API if a user's browser has valid credentials cached for the webserver while the user visits the malicious website"
     - name: "api_requires_authentication"
       type: "bool"
       default: "true"
diff -ru dnsdist-2.0.2.orig/dnsdist-web.cc dnsdist-2.0.2/dnsdist-web.cc
--- dnsdist-2.0.2.orig/dnsdist-web.cc	2025-11-27 14:25:28.000000000 +0100
+++ dnsdist-2.0.2/dnsdist-web.cc	2026-02-23 15:01:37.072518008 +0100
@@ -379,9 +379,10 @@
 {
   const auto origin = req.headers.find("Origin");
   if (origin != req.headers.end()) {
+    const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
     if (req.method == "OPTIONS") {
       /* Pre-flight request */
-      if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_apiReadWrite) {
+      if (config.d_apiReadWrite) {
         resp.headers["Access-Control-Allow-Methods"] = "GET, PUT";
       }
       else {
@@ -390,10 +391,13 @@
       resp.headers["Access-Control-Allow-Headers"] = "Authorization, X-API-Key";
     }
 
-    resp.headers["Access-Control-Allow-Origin"] = origin->second;
+    if (config.d_webServerAllowCrossOriginRequests) {
+      resp.headers["Access-Control-Allow-Origin"] = origin->second;
+      resp.headers["Vary"] = "Origin"; // prevents cached data to be used for a different Origin
 
-    if (isAStatsRequest(req) || isAnAPIRequestAllowedWithWebAuth(req)) {
-      resp.headers["Access-Control-Allow-Credentials"] = "true";
+      if (isAStatsRequest(req) || isAnAPIRequestAllowedWithWebAuth(req)) {
+        resp.headers["Access-Control-Allow-Credentials"] = "true";
+      }
     }
   }
 }
diff -ru dnsdist-2.0.2.orig/docs/reference/config.rst dnsdist-2.0.2/docs/reference/config.rst
--- dnsdist-2.0.2.orig/docs/reference/config.rst	2025-11-27 14:25:28.000000000 +0100
+++ dnsdist-2.0.2/docs/reference/config.rst	2026-02-23 15:01:37.073639579 +0100
@@ -477,6 +477,7 @@
   * ``apiKey=newKey``: string - Changes the API Key (set to an empty string do disable it). Since 1.7.0 the key should be hashed and salted via the :func:`hashPassword` command.
   * ``customHeaders={[str]=str,...}``: map of string - Allows setting custom headers and removing the defaults.
   * ``acl=newACL``: string - List of IP addresses, as a string, that are allowed to open a connection to the web server. Defaults to "127.0.0.1, ::1".
+  * ``allowCrossOriginRequests``: bool - Whether the webserver allows cross-origin HTTP requests. This might allow a malicious website to read metrics provided by the API if a user's browser has valid credentials cached for the webserver while the user visits the malicious website. Default to false.
   * ``apiRequiresAuthentication``: bool - Whether access to the API (/api endpoints) require a valid API key. Defaults to true.
   * ``dashboardRequiresAuthentication``: bool - Whether access to the internal dashboard requires a valid password. Defaults to true.
   * ``statsRequireAuthentication``: bool - Whether access to the statistics (/metrics and /jsonstat endpoints) require a valid password or API key. Defaults to true.
