This is an automated email from the ASF dual-hosted git repository.

ricardozanini pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new 9c4509180ba kie-tools#3308: [cors-proxy] CORS code-scanning issues 
(#3327)
9c4509180ba is described below

commit 9c4509180ba82c24c1878c7281cce8f6b01e982b
Author: Fabrizio Antonangeli <[email protected]>
AuthorDate: Mon Dec 1 16:04:04 2025 +0100

    kie-tools#3308: [cors-proxy] CORS code-scanning issues (#3327)
---
 packages/cors-proxy-image/Containerfile            |   4 +-
 packages/cors-proxy-image/README.md                |  10 +-
 packages/cors-proxy-image/env/index.js             |   8 +-
 packages/cors-proxy-image/package.json             |   2 +-
 packages/cors-proxy/README.md                      |  16 +-
 packages/cors-proxy/env/index.js                   |  10 +-
 packages/cors-proxy/package.json                   |   4 +-
 packages/cors-proxy/src/index.ts                   |  17 +-
 packages/cors-proxy/src/proxy/ExpressCorsProxy.ts  |  14 +-
 packages/cors-proxy/src/proxy/server.ts            |  14 +-
 packages/cors-proxy/tests/index.test.ts            | 106 +++++++++----
 packages/cors-proxy/tests/server.test.ts           | 175 +++++++++++++++++++++
 packages/online-editor/package.json                |   2 +-
 .../server/config/index.js                         |   2 +-
 .../server/server.js                               |   9 ++
 packages/serverless-logic-web-tools/package.json   |   4 +-
 .../serverless-workflow-dev-ui-webapp/package.json |   4 +-
 packages/sonataflow-deployment-webapp/package.json |   4 +-
 packages/sonataflow-dev-app/README.md              |   6 +-
 .../sonataflow-dev-app/src/MockData/graphql.js     |   2 +-
 packages/sonataflow-dev-app/src/config/index.js    |   2 +-
 packages/sonataflow-dev-app/src/server.js          |   9 ++
 .../package.json                                   |   4 +-
 23 files changed, 352 insertions(+), 76 deletions(-)

diff --git a/packages/cors-proxy-image/Containerfile 
b/packages/cors-proxy-image/Containerfile
index f54565738fe..84450e5b32c 100644
--- a/packages/cors-proxy-image/Containerfile
+++ b/packages/cors-proxy-image/Containerfile
@@ -18,7 +18,7 @@
 FROM --platform=linux/amd64 registry.access.redhat.com/ubi9/ubi-minimal:9.5
 
 ARG CORS_PROXY_DEFAULT_PORT=8080
-ARG CORS_PROXY_DEFAULT_ORIGIN=*
+ARG CORS_PROXY_DEFAULT_ALLOWED_ORIGINS=
 ARG CORS_PROXY_DEFAULT_VERBOSE=false
 
 ENV HOME          /home/kie-sandbox
@@ -26,7 +26,7 @@ ENV NVM_DIR       $HOME/.nvm
 ENV NODE_VERSION  v22.14.0
 
 ENV CORS_PROXY_HTTP_PORT=$CORS_PROXY_DEFAULT_PORT
-ENV CORS_PROXY_ORIGIN=$CORS_PROXY_DEFAULT_ORIGIN
+ENV CORS_PROXY_ALLOWED_ORIGINS=$CORS_PROXY_DEFAULT_ALLOWED_ORIGINS
 ENV CORS_PROXY_VERBOSE=$CORS_PROXY_DEFAULT_VERBOSE
 
 RUN mkdir $HOME \
diff --git a/packages/cors-proxy-image/README.md 
b/packages/cors-proxy-image/README.md
index fc900cb27ee..98f17ba6100 100644
--- a/packages/cors-proxy-image/README.md
+++ b/packages/cors-proxy-image/README.md
@@ -39,7 +39,7 @@ export CORS_PROXY_IMAGE__imageAccount=<account>
 export CORS_PROXY_IMAGE__imageName=<image-name>
 export CORS_PROXY_IMAGE__imageBuildTag=<image-tag>
 export CORS_PROXY_IMAGE__imagePort=<port>
-export CORS_PROXY_IMAGE__imageOrigin=<origin>
+export CORS_PROXY_IMAGE__imageAllowedOrigins=<allowed-origins>  # 
Comma-separated list
 export CORS_PROXY_IMAGE__imageVerbose=<verbose>
 ```
 
@@ -62,7 +62,13 @@ docker images
 Start up a new container with:
 
 ```bash
-docker run -p 8080:8080 -i --rm docker.io/apache/incubator-kie-cors-proxy:main
+docker run -p 8080:8080 -i --rm -e 
CORS_PROXY_ALLOWED_ORIGINS="http://localhost:9001"; 
docker.io/apache/incubator-kie-cors-proxy:main
+```
+
+Or in production:
+
+```bash
+docker run -p 8080:8080 -i --rm -e 
CORS_PROXY_ALLOWED_ORIGINS="https://example.com,https://other.example.com"; 
docker.io/apache/incubator-kie-cors-proxy:main
 ```
 
 The service will be up at http://localhost:8080
diff --git a/packages/cors-proxy-image/env/index.js 
b/packages/cors-proxy-image/env/index.js
index 3370b84838f..411050ddea1 100644
--- a/packages/cors-proxy-image/env/index.js
+++ b/packages/cors-proxy-image/env/index.js
@@ -44,9 +44,9 @@ module.exports = composeEnv([rootEnv], {
       default: corsProxyEnv.env.corsProxy.dev.port,
       description: "HTTP port where the CORS proxy will run inside this 
image.",
     },
-    CORS_PROXY_IMAGE__imageOrigin: {
-      default: corsProxyEnv.env.corsProxy.dev.origin,
-      description: "Origin to be used for the CORS proxy running inside this 
image.",
+    CORS_PROXY_IMAGE__imageAllowedOrigins: {
+      default: corsProxyEnv.env.corsProxy.dev.allowedOrigins,
+      description: "Comma-separated list of allowed origins for the CORS proxy 
running inside this image.",
     },
     CORS_PROXY_IMAGE__imageVerbose: {
       default: false,
@@ -62,7 +62,7 @@ module.exports = composeEnv([rootEnv], {
           name: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageName),
           buildTag: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageBuildTag),
           port: getOrDefault(this.vars.CORS_PROXY_IMAGE__imagePort),
-          origin: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageOrigin),
+          allowedOrigins: 
getOrDefault(this.vars.CORS_PROXY_IMAGE__imageAllowedOrigins),
           verbose: getOrDefault(this.vars.CORS_PROXY_IMAGE__imageVerbose),
         },
       },
diff --git a/packages/cors-proxy-image/package.json 
b/packages/cors-proxy-image/package.json
index 5a1ce8ca09f..d518b2b0fab 100644
--- a/packages/cors-proxy-image/package.json
+++ b/packages/cors-proxy-image/package.json
@@ -19,7 +19,7 @@
     "copy:cors-proxy-package": "run-script-os",
     "copy:cors-proxy-package:linux:darwin": "cp -R 
./node_modules/@kie-tools/cors-proxy/dist/ dist-dev/cors-proxy/",
     "copy:cors-proxy-package:win32": "pnpm powershell \"Copy-Item -R 
./node_modules/@kie-tools/cors-proxy/dist/ dist-dev/cors-proxy/\"",
-    "docker:build": "kie-tools--image-builder build -r \"$(build-env 
corsProxyImage.image.registry)\" -a \"$(build-env 
corsProxyImage.image.account)\" -n \"$(build-env corsProxyImage.image.name)\" 
-t \"$(build-env corsProxyImage.image.buildTag)\" --build-arg 
\"CORS_PROXY_DEFAULT_HTTP_PORT=$(build-env corsProxyImage.image.port)\" 
--build-arg \"CORS_PROXY_DEFAULT_ORIGIN=$(build-env 
corsProxyImage.image.origin)\" --build-arg 
\"CORS_PROXY_DEFAULT_VERBOSE=$(build-env corsProxyImage.image.verbose)\""
+    "docker:build": "kie-tools--image-builder build -r \"$(build-env 
corsProxyImage.image.registry)\" -a \"$(build-env 
corsProxyImage.image.account)\" -n \"$(build-env corsProxyImage.image.name)\" 
-t \"$(build-env corsProxyImage.image.buildTag)\" --build-arg 
\"CORS_PROXY_DEFAULT_PORT=$(build-env corsProxyImage.image.port)\" --build-arg 
\"CORS_PROXY_DEFAULT_ALLOWED_ORIGINS=$(build-env 
corsProxyImage.image.allowedOrigins)\" --build-arg 
\"CORS_PROXY_DEFAULT_VERBOSE=$(build-env corsProxyImag [...]
   },
   "devDependencies": {
     "@kie-tools/cors-proxy": "workspace:*",
diff --git a/packages/cors-proxy/README.md b/packages/cors-proxy/README.md
index 78c966bc170..9a4edc4d157 100644
--- a/packages/cors-proxy/README.md
+++ b/packages/cors-proxy/README.md
@@ -23,8 +23,8 @@ This package contains a `cors-proxy`, which is a simple 
Node.js application inte
 
 The `cors-proxy` can be configured via environment variables:
 
-- CORS_PROXY_HTTP_PORT: Sets the HTTP Port the proxy should listen to
-- CORS_PROXY_ORIGIN: Sets the value of the 'Access-Control-Allow-Origin' 
header. Defaults to `*`.
+- CORS_PROXY_ALLOWED_ORIGINS: **Required** Comma-separated list of allowed 
origins. Wildcard `*` is not allowed for security reasons.
+- CORS_PROXY_HTTP_PORT: Sets the HTTP Port the proxy should listen to. 
Defaults to `8080`
 - CORS_PROXY_VERBOSE: Allows the proxy to run in verbose mode... useful to 
trace requests on development environments. Defaults to `false`
 - CORS_PROXY_USE_HTTP_FOR_HOSTS: Comma-separated list of hosts that should use 
the `http` protocol for proxied requests. Defaults to an empty list.
 - HTTP_PROXY or HTTPS_PROXY: Url of a proxy that will be used to proxy the 
requests `cors-proxy` is already proxying.
@@ -34,7 +34,7 @@ For example:
 
 ```bash
 export CORS_PROXY_HTTP_PORT=8080
-export CORS_PROXY_ORIGIN=*
+export 
CORS_PROXY_ALLOWED_ORIGINS="https://example.com,https://other.example.com";
 export CORS_PROXY_VERBOSE=false
 export CORS_PROXY_USE_HTTP_FOR_HOSTS="localhost:8080,localhost:8081"
 ```
@@ -56,14 +56,14 @@ node ./dist/index.js
 # Running `cors-proxy` in dev mode.
 
 ```bash
-pnpm -F @kie-tools/cors-proxy start
+CORS_PROXY__allowedOrigins="http://localhost:9001"; pnpm -F 
@kie-tools/cors-proxy start
 ```
 
 You can also use the following envs to configure `cors-proxy` when starting in 
dev-mode:
 
 ```bash
+export CORS_PROXY__allowedOrigins="http://localhost:9001";
 export CORS_PROXY__port=*
-export CORS_PROXY__origin=*
 export CORS_PROXY__verbose=false
 export CORS_PROXY__useHttpForHosts="localhost:8080,localhost:8081"
 ```
@@ -83,7 +83,7 @@ mitmweb --set listen_port=<PORT> --showhost
 Now set the HTTPS_PROXY and NODE_EXTRA_CA_CERTS environment variables before 
starting the `cors-proxy` service:
 
 ```bash
-export HTTPS_PROXY=http://localhost:<PORT
+export HTTPS_PROXY=http://localhost:<PORT>
 export NODE_EXTRA_CA_CERTS=~/.mitmproxy/mitmproxy-ca-cert.pem
 ```
 
@@ -93,9 +93,9 @@ Set the rest of the environment variables and start the 
`cors-proxy` service:
 
 ```bash
 export CORS_PROXY__port=*
-export CORS_PROXY__origin=*
+export CORS_PROXY__allowedOrigins="http://localhost:9001";
 
-pnpm -F @kie-tools/cors-proxy start
+ pnpm -F @kie-tools/cors-proxy start
 ```
 
 ---
diff --git a/packages/cors-proxy/env/index.js b/packages/cors-proxy/env/index.js
index 41803812c85..c7ace6d1fed 100644
--- a/packages/cors-proxy/env/index.js
+++ b/packages/cors-proxy/env/index.js
@@ -21,14 +21,14 @@ const { varsWithName, composeEnv, getOrDefault } = 
require("@kie-tools-scripts/b
 
 module.exports = composeEnv([require("@kie-tools/root-env/env")], {
   vars: varsWithName({
+    CORS_PROXY__allowedOrigins: {
+      default: "http://localhost:9001";,
+      description: "Comma-separated list of allowed origins used to set on the 
'Access-Control-Allow-Origin' header",
+    },
     CORS_PROXY__port: {
       default: 8080,
       description: "HTTP Port the proxy should listen to",
     },
-    CORS_PROXY__origin: {
-      default: "*",
-      description: "Value to set on the 'Access-Control-Allow-Origin' header",
-    },
     CORS_PROXY__verbose: {
       default: true,
       description: "Allows the proxy to run in verbose mode... useful to trace 
requests on development environments",
@@ -42,8 +42,8 @@ module.exports = 
composeEnv([require("@kie-tools/root-env/env")], {
     return {
       corsProxy: {
         dev: {
+          allowedOrigins: getOrDefault(this.vars.CORS_PROXY__allowedOrigins),
           port: getOrDefault(this.vars.CORS_PROXY__port),
-          origin: getOrDefault(this.vars.CORS_PROXY__origin),
           verbose: getOrDefault(this.vars.CORS_PROXY__verbose),
           useHttpForHosts: getOrDefault(this.vars.CORS_PROXY__useHttpForHosts),
         },
diff --git a/packages/cors-proxy/package.json b/packages/cors-proxy/package.json
index 123090ca0bc..82cc1781adf 100644
--- a/packages/cors-proxy/package.json
+++ b/packages/cors-proxy/package.json
@@ -21,8 +21,8 @@
     "build:prod": "pnpm lint && pnpm test && rimraf dist && webpack",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
     "start": "run-script-os",
-    "start:darwin:linux": "pnpm build:dev && cross-env 
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts) 
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port) 
CORS_PROXY_ORIGIN=$(build-env corsProxy.dev.origin) 
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js",
-    "start:win32": "pnpm build:dev && pnpm powershell \"cross-env 
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts) 
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port) 
CORS_PROXY_ORIGIN=$(build-env corsProxy.dev.origin) 
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js\"",
+    "start:darwin:linux": "pnpm build:dev && cross-env 
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts) 
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port) 
CORS_PROXY_ALLOWED_ORIGINS=$(build-env corsProxy.dev.allowedOrigins) 
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js",
+    "start:win32": "pnpm build:dev && pnpm powershell \"cross-env 
CORS_PROXY_USE_HTTP_FOR_HOSTS=$(build-env corsProxy.dev.useHttpForHosts) 
CORS_PROXY_HTTP_PORT=$(build-env corsProxy.dev.port) 
CORS_PROXY_ALLOWED_ORIGINS=$(build-env corsProxy.dev.allowedOrigins) 
CORS_PROXY_VERBOSE=$(build-env corsProxy.dev.verbose) node dist/index.js\"",
     "test": "run-script-if --ignore-errors \"$(build-env 
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest 
--silent --verbose --passWithNoTests\""
   },
   "dependencies": {
diff --git a/packages/cors-proxy/src/index.ts b/packages/cors-proxy/src/index.ts
index f3d273f45d2..6020b615b0e 100644
--- a/packages/cors-proxy/src/index.ts
+++ b/packages/cors-proxy/src/index.ts
@@ -27,10 +27,25 @@ function getPort(): number {
   return 8080;
 }
 
+function getAllowedOrigins(): string[] {
+  const origins = process.env.CORS_PROXY_ALLOWED_ORIGINS || "";
+  const originsList = origins.split(",").map((o) => o.trim());
+
+  if (originsList.some((o) => o === "")) {
+    throw new Error("Invalid origin: empty origins are not allowed in 
CORS_PROXY_ALLOWED_ORIGINS.");
+  }
+
+  if (originsList.some((o) => o === "*")) {
+    throw new Error('Invalid origin: wildcard "*" is not allowed in 
CORS_PROXY_ALLOWED_ORIGINS.');
+  }
+
+  return originsList;
+}
+
 export const run = () => {
   startServer({
+    allowedOrigins: getAllowedOrigins(),
     port: getPort(),
-    origin: process.env.CORS_PROXY_ORIGIN ?? "*",
     verbose: process.env.CORS_PROXY_VERBOSE === "true",
     hostsToUseHttp: (process.env.CORS_PROXY_USE_HTTP_FOR_HOSTS || 
undefined)?.split(",") ?? [],
   });
diff --git a/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts 
b/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
index 6cede0a2a37..9ae560ab737 100644
--- a/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
+++ b/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
@@ -37,7 +37,7 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
 
   constructor(
     private readonly args: {
-      origin: string;
+      allowedOrigins: string[];
       verbose: boolean;
       hostsToUseHttp: string[];
     }
@@ -46,7 +46,6 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
 
     this.logger.debug("");
     this.logger.debug("Proxy Configuration:");
-    this.logger.debug("* Accept Origin Header: ", `"${args.origin}"`);
     this.logger.debug("* Verbose: ", args.verbose);
     this.logger.debug("");
   }
@@ -92,9 +91,6 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
       });
       this.logger.debug("Proxy Response status: ", proxyResponse.status);
 
-      // Setting up the headers to the original response...
-      res.header("Access-Control-Allow-Origin", this.args.origin);
-
       if (req.method == "OPTIONS") {
         res.header("Access-Control-Allow-Methods", 
info.corsConfig?.allowMethods.join(", ") ?? "*");
         res.header("Access-Control-Allow-Headers", 
info.corsConfig?.allowHeaders.join(", ") ?? "*");
@@ -105,6 +101,9 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
       }
 
       proxyResponse.headers.forEach((value, header) => {
+        if (header.toLowerCase() === "access-control-allow-origin") {
+          return;
+        }
         if (!info.corsConfig || 
info.corsConfig.exposeHeaders.includes(header)) {
           res.setHeader(header, value);
         }
@@ -140,7 +139,12 @@ export class ExpressCorsProxy implements 
CorsProxy<Request, Response> {
   }
 
   private resolveRequestInfo(request: Request): ProxyRequestInfo {
+    const origin = request.header("origin");
     const targetUrl: string = (request.headers[CorsProxyHeaderKeys.TARGET_URL] 
as string) ?? request.url;
+    if (!origin || !this.args.allowedOrigins.includes(origin)) {
+      throw new Error(`Origin ${origin} is not allowed`);
+    }
+
     if (!targetUrl || targetUrl == "/") {
       throw new Error("Couldn't resolve the target URL...");
     }
diff --git a/packages/cors-proxy/src/proxy/server.ts 
b/packages/cors-proxy/src/proxy/server.ts
index 97de03fac2a..cb71c6e9cdb 100644
--- a/packages/cors-proxy/src/proxy/server.ts
+++ b/packages/cors-proxy/src/proxy/server.ts
@@ -23,8 +23,8 @@ import * as cors from "cors";
 import { ExpressCorsProxy } from "./ExpressCorsProxy";
 
 export type ServerArgs = {
+  allowedOrigins: string[];
   port: number;
-  origin: string;
   verbose: boolean;
   hostsToUseHttp: string[];
 };
@@ -32,7 +32,7 @@ export type ServerArgs = {
 export const startServer = (args: ServerArgs): void => {
   console.log("Starting CORS proxy...");
   console.log("====================================================");
-  console.log(`Origin:                     ${args.origin}`);
+  console.log(`Allowed Origins:            ${args.allowedOrigins.join(", ")}`);
   console.log(`Port:                       ${args.port}`);
   console.log(`Verbose:                    ${args.verbose}`);
   console.log(`Hosts to proxy with HTTP:   ${args.hostsToUseHttp}`);
@@ -44,7 +44,15 @@ export const startServer = (args: ServerArgs): void => {
 
   const proxy = new ExpressCorsProxy(args);
 
-  const corsHandler = cors({ origin: args.origin });
+  const corsHandler = cors({
+    origin: (origin, cb) => {
+      if (!origin || !args.allowedOrigins.includes(origin)) {
+        return cb(null, false);
+      }
+
+      return cb(null, origin);
+    },
+  });
 
   app.use(corsHandler);
   app.options("/", corsHandler); // enable pre-flight requests
diff --git a/packages/cors-proxy/tests/index.test.ts 
b/packages/cors-proxy/tests/index.test.ts
index e1300eaedaa..393a5601236 100644
--- a/packages/cors-proxy/tests/index.test.ts
+++ b/packages/cors-proxy/tests/index.test.ts
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+process.env.CORS_PROXY_ALLOWED_ORIGINS = "http://localhost:9001";;
+
 import { startServer } from "../src/proxy";
 import { run } from "../src";
 
@@ -28,8 +30,8 @@ jest.mock("../src/proxy", () => ({
 
 function setEnv(env: Record<string, string>) {
   process.env = {
-    ...env,
     ...process.env,
+    ...env,
   };
 }
 
@@ -39,58 +41,104 @@ describe("index.ts test", () => {
     jest.resetAllMocks();
   });
 
-  it("Default values", () => {
-    run();
-
-    expect(startServer).toHaveBeenCalledWith(
-      expect.objectContaining({
-        port: 8080,
-        origin: "*",
-        verbose: false,
-      })
-    );
-  });
-
   it("Custom port", () => {
     setEnv({
       CORS_PROXY_HTTP_PORT: "90",
+      CORS_PROXY_ALLOWED_ORIGINS: "http://example.com";,
     });
 
     run();
     expect(startServer).toHaveBeenCalledWith(
       expect.objectContaining({
         port: 90,
-        origin: "*",
+        allowedOrigins: ["http://example.com";],
         verbose: false,
       })
     );
   });
 
-  it("Custom origin", () => {
+  it("Verbose mode", () => {
     setEnv({
-      CORS_PROXY_ORIGIN: "http://localhost";,
+      CORS_PROXY_ALLOWED_ORIGINS: "http://example.com";,
+      CORS_PROXY_VERBOSE: "true",
     });
     run();
     expect(startServer).toHaveBeenCalledWith(
       expect.objectContaining({
         port: 8080,
-        origin: "http://localhost";,
-        verbose: false,
+        allowedOrigins: ["http://example.com";],
+        verbose: true,
       })
     );
   });
 
-  it("Verbose", () => {
-    setEnv({
-      CORS_PROXY_VERBOSE: "true",
+  describe("Allowed origins configuration", () => {
+    it("Single allowed origin", () => {
+      setEnv({
+        CORS_PROXY_ALLOWED_ORIGINS: "http://example.com";,
+      });
+
+      run();
+      expect(startServer).toHaveBeenCalledWith(
+        expect.objectContaining({
+          port: 8080,
+          allowedOrigins: ["http://example.com";],
+          verbose: false,
+        })
+      );
+    });
+
+    it("Multiple allowed origins", () => {
+      setEnv({
+        CORS_PROXY_ALLOWED_ORIGINS: 
"http://example.com,https://other.example.com,http://localhost:9001";,
+      });
+
+      run();
+      expect(startServer).toHaveBeenCalledWith(
+        expect.objectContaining({
+          port: 8080,
+          allowedOrigins: ["http://example.com";, "https://other.example.com";, 
"http://localhost:9001";],
+          verbose: false,
+        })
+      );
+    });
+
+    it("Should throw an error when allowed origins is not set", () => {
+      delete process.env.CORS_PROXY_ALLOWED_ORIGINS;
+
+      expect(() => {
+        run();
+      }).toThrow(new Error("Invalid origin: empty origins are not allowed in 
CORS_PROXY_ALLOWED_ORIGINS."));
+    });
+
+    it("Should throw an error when allowed origins is empty", () => {
+      setEnv({
+        CORS_PROXY_ALLOWED_ORIGINS: "",
+      });
+
+      expect(() => {
+        run();
+      }).toThrow(new Error("Invalid origin: empty origins are not allowed in 
CORS_PROXY_ALLOWED_ORIGINS."));
+    });
+
+    it("Should throw an error when wildcard '*' is in the list", () => {
+      setEnv({
+        CORS_PROXY_ALLOWED_ORIGINS: "http://example.com,*";,
+      });
+
+      expect(() => {
+        run();
+      }).toThrow(new Error('Invalid origin: wildcard "*" is not allowed in 
CORS_PROXY_ALLOWED_ORIGINS.'));
+    });
+
+    it("Should throw an error when there are empty origins in the list", () => 
{
+      setEnv({
+        CORS_PROXY_ALLOWED_ORIGINS: 
"http://example.com,,https://other.example.com";,
+      });
+
+      expect(() => {
+        run();
+      }).toThrow(new Error("Invalid origin: empty origins are not allowed in 
CORS_PROXY_ALLOWED_ORIGINS."));
     });
-    run();
-    expect(startServer).toHaveBeenCalledWith(
-      expect.objectContaining({
-        port: 8080,
-        origin: "*",
-        verbose: true,
-      })
-    );
   });
 });
diff --git a/packages/cors-proxy/tests/server.test.ts 
b/packages/cors-proxy/tests/server.test.ts
new file mode 100644
index 00000000000..77b35c3cd9c
--- /dev/null
+++ b/packages/cors-proxy/tests/server.test.ts
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+const originalCors = jest.requireActual("cors");
+const originalExpress = jest.requireActual("express");
+
+const corsMock = jest.fn((options?: any) => {
+  return originalCors(options);
+});
+
+jest.mock("node-fetch", () => jest.fn());
+jest.mock("cors", () => corsMock);
+jest.mock("express", () => () => {
+  const app = originalExpress();
+  app.listen = jest.fn(() => {});
+  return app;
+});
+
+import { ServerArgs, startServer } from "../src/proxy/server";
+
+describe("CORS handler logic test", () => {
+  beforeEach(() => {
+    jest.clearAllMocks();
+  });
+
+  describe("Single origin in allowedOrigins", () => {
+    it("should allow requests from origin http://localhost:9000";, (done) => {
+      const args: ServerArgs = {
+        allowedOrigins: ["http://localhost:9000";],
+        port: 8080,
+        verbose: false,
+        hostsToUseHttp: [],
+      };
+
+      startServer(args);
+
+      const req: any = {
+        headers: {
+          origin: "http://localhost:9000";,
+        },
+        method: "GET",
+      };
+
+      const res: any = {
+        statusCode: 200,
+        setHeader: jest.fn(),
+        getHeader: jest.fn(),
+      };
+
+      const next = function () {
+        
expect(res.setHeader).toHaveBeenCalledWith("Access-Control-Allow-Origin", 
"http://localhost:9000";);
+        done();
+      };
+
+      const corsMiddleware = corsMock.mock.results[0].value;
+      corsMiddleware(req, res, next);
+    });
+
+    it("should not allow requests from non-allowed origin", (done) => {
+      const args: ServerArgs = {
+        allowedOrigins: ["http://localhost:9000";],
+        port: 8080,
+        verbose: false,
+        hostsToUseHttp: [],
+      };
+
+      startServer(args);
+
+      const req: any = {
+        headers: {
+          origin: "http://notvalid:8080";,
+        },
+        method: "GET",
+      };
+
+      const res: any = {
+        statusCode: 200,
+        setHeader: jest.fn(),
+        getHeader: jest.fn(),
+      };
+
+      const next = function () {
+        expect(res.setHeader).not.toHaveBeenCalled();
+        done();
+      };
+
+      const corsMiddleware = corsMock.mock.results[0].value;
+      corsMiddleware(req, res, next);
+    });
+  });
+
+  describe("Multiple origins in allowedOrigins", () => {
+    it.each(["http://example.com";, "http://staging.example.com";])(
+      'should allow requests from %s allowed origin with allowedOrigins: 
["http://example.com";, "http://staging.example.com";]',
+      (origin, done) => {
+        const args: ServerArgs = {
+          allowedOrigins: ["http://example.com";, "http://staging.example.com";],
+          port: 8080,
+          verbose: false,
+          hostsToUseHttp: [],
+        };
+
+        startServer(args);
+
+        const req: any = {
+          headers: {
+            origin,
+          },
+          method: "GET",
+        };
+
+        const res: any = {
+          statusCode: 200,
+          setHeader: jest.fn(),
+          getHeader: jest.fn(),
+        };
+
+        const next = function () {
+          
expect(res.setHeader).toHaveBeenCalledWith("Access-Control-Allow-Origin", 
origin);
+          done();
+        };
+
+        const corsMiddleware = corsMock.mock.results[0].value;
+        corsMiddleware(req, res, next);
+      }
+    );
+
+    it("should not allow requests from non-allowed origin", (done) => {
+      const args: ServerArgs = {
+        allowedOrigins: ["http://example.com";, "http://staging.example.com";],
+        port: 8080,
+        verbose: false,
+        hostsToUseHttp: [],
+      };
+
+      startServer(args);
+
+      const req: any = {
+        headers: {
+          origin: "http://notvalid:9000";,
+        },
+        method: "GET",
+      };
+
+      const res: any = {
+        statusCode: 200,
+        setHeader: jest.fn(),
+        getHeader: jest.fn(),
+      };
+
+      const next = function () {
+        expect(res.setHeader).not.toHaveBeenCalled();
+        done();
+      };
+
+      const corsMiddleware = corsMock.mock.results[0].value;
+      corsMiddleware(req, res, next);
+    });
+  });
+});
diff --git a/packages/online-editor/package.json 
b/packages/online-editor/package.json
index 5d81cd629ad..7bdc0d5a7ec 100644
--- a/packages/online-editor/package.json
+++ b/packages/online-editor/package.json
@@ -19,7 +19,7 @@
     "build:prod": "pnpm lint && pnpm test && rimraf dist && webpack && pnpm 
test-e2e",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
     "start": "concurrently 'pnpm start:cors-proxy' 'pnpm 
start:extended-services' 'pnpm start:kie-sandbox' 'pnpm 
start:kie-sandbox-accelerator-quarkus'",
-    "start:cors-proxy": "cross-env 
CORS_PROXY__useHttpForHosts=\"localhost:$(build-env 
kieSandboxAcceleratorQuarkus.dev.port)\" npm --prefix 
./node_modules/@kie-tools/cors-proxy run start",
+    "start:cors-proxy": "cross-env 
CORS_PROXY__origin=https://localhost:$(build-env onlineEditor.dev.port) 
CORS_PROXY__useHttpForHosts=\"localhost:$(build-env 
kieSandboxAcceleratorQuarkus.dev.port)\" npm --prefix 
./node_modules/@kie-tools/cors-proxy run start",
     "start:extended-services": "cross-env 
EXTENDED_SERVICES_JAVA__host=\"0.0.0.0\" npm --prefix 
./node_modules/@kie-tools/extended-services-java run start",
     "start:kie-sandbox": "cross-env EXTENDED_SERVICES_JAVA__host=\"0.0.0.0\" 
webpack serve --host 0.0.0.0 --env dev",
     "start:kie-sandbox-accelerator-quarkus": "npm --prefix 
./node_modules/@kie-tools/kie-sandbox-accelerator-quarkus run start",
diff --git 
a/packages/runtime-tools-process-dev-ui-webapp/server/config/index.js 
b/packages/runtime-tools-process-dev-ui-webapp/server/config/index.js
index d6ec683bf1a..e9c4db6bd6e 100644
--- a/packages/runtime-tools-process-dev-ui-webapp/server/config/index.js
+++ b/packages/runtime-tools-process-dev-ui-webapp/server/config/index.js
@@ -19,7 +19,7 @@
 const commonConfig = {
   env: process.env.NODE_ENV || "development",
   port: parseInt(process.env.PORT, 10) || 4000,
-  corsDomain: process.env.CORS_DOMAIN || "*",
+  corsDomain: process.env.CORS_DOMAIN,
 };
 
 module.exports = commonConfig;
diff --git a/packages/runtime-tools-process-dev-ui-webapp/server/server.js 
b/packages/runtime-tools-process-dev-ui-webapp/server/server.js
index 8cc617e7799..4f674305510 100644
--- a/packages/runtime-tools-process-dev-ui-webapp/server/server.js
+++ b/packages/runtime-tools-process-dev-ui-webapp/server/server.js
@@ -53,6 +53,15 @@ function listen() {
     console.log(`The server is running and listening at 
http://localhost:${port}`);
   });
 }
+
+// validate corsDomain, required for CodeQL scan
+if (!config.corsDomain) {
+  throw new Error("Invalid CORS_DOMAIN: Please specify a domain.");
+}
+if (config.corsDomain.trim() === "*") {
+  throw new Error('Invalid CORS_DOMAIN: wildcard "*" is not allowed.');
+}
+
 // parse application/x-www-form-urlencoded
 app.use(bodyParser.urlencoded({ extended: false }));
 
diff --git a/packages/serverless-logic-web-tools/package.json 
b/packages/serverless-logic-web-tools/package.json
index 7595c6e111b..b5d7d8b5901 100644
--- a/packages/serverless-logic-web-tools/package.json
+++ b/packages/serverless-logic-web-tools/package.json
@@ -21,9 +21,9 @@
     "cy:run": "cypress run --headed -b chrome --project e2e-tests --config 
baseUrl=$(build-env serverlessLogicWebTools.dev.cypressUrl)",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
     "postreport": "jrm ./dist-tests-e2e/junit-transformed.xml 
\"./dist-tests-e2e/junit-report*.xml\"",
-    "start": "concurrently 'pnpm start:dev-webapp' 'pnpm 
start:sonataflow-dev-app'",
+    "start": "concurrently --no-colors 'pnpm start:dev-webapp' 'pnpm 
start:sonataflow-dev-app'",
     "start:dev-webapp": "webpack serve --host 0.0.0.0 --env dev",
-    "start:sonataflow-dev-app": "npm --prefix 
./node_modules/@kie-tools/sonataflow-dev-app run start",
+    "start:sonataflow-dev-app": "CORS_DOMAIN=https://localhost:$(build-env 
serverlessLogicWebTools.dev.port) npm --prefix 
./node_modules/@kie-tools/sonataflow-dev-app run start",
     "test": "run-script-if --ignore-errors \"$(build-env 
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest 
--silent --verbose --passWithNoTests\"",
     "test-e2e": "run-script-if --ignore-errors \"$(build-env 
endToEndTests.ignoreFailures)\" --bool \"$(build-env endToEndTests.run)\" 
--then  \"pnpm rimraf ./dist-tests-e2e\" \"pnpm start-server-and-test start 
https-get://0.0.0.0:$(build-env serverlessLogicWebTools.dev.port) cy:run\" 
\"pnpm postreport\""
   },
diff --git a/packages/serverless-workflow-dev-ui-webapp/package.json 
b/packages/serverless-workflow-dev-ui-webapp/package.json
index b4df4f85a68..a73031c7b76 100644
--- a/packages/serverless-workflow-dev-ui-webapp/package.json
+++ b/packages/serverless-workflow-dev-ui-webapp/package.json
@@ -22,9 +22,9 @@
     "build:dev": "rimraf dist && webpack --env dev",
     "build:prod": "pnpm lint && rimraf dist && webpack",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
-    "start": "concurrently 'pnpm start:dev-webapp' 'pnpm 
start:sonataflow-dev-app'",
+    "start": "concurrently --no-colors 'pnpm start:dev-webapp' 'pnpm 
start:sonataflow-dev-app'",
     "start:dev-webapp": "webpack serve --host 0.0.0.0 --env dev",
-    "start:sonataflow-dev-app": "npm --prefix 
./node_modules/@kie-tools/sonataflow-dev-app run start",
+    "start:sonataflow-dev-app": "CORS_DOMAIN=http://localhost:$(build-env 
runtimeToolsDevUiWebapp.dev.port) npm --prefix 
./node_modules/@kie-tools/sonataflow-dev-app run start",
     "test": "run-script-if --ignore-errors \"$(build-env 
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest 
--silent --verbose --passWithNoTests\""
   },
   "dependencies": {
diff --git a/packages/sonataflow-deployment-webapp/package.json 
b/packages/sonataflow-deployment-webapp/package.json
index 725b064b7a8..8f60b11e782 100644
--- a/packages/sonataflow-deployment-webapp/package.json
+++ b/packages/sonataflow-deployment-webapp/package.json
@@ -18,9 +18,9 @@
     "build:dev": "rimraf dist && webpack --env dev",
     "build:prod": "pnpm lint && pnpm test && rimraf dist && webpack",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
-    "start": "concurrently 'pnpm start:dev-webapp' 'pnpm 
start:sonataflow-dev-app'",
+    "start": "concurrently --no-colors 'pnpm start:dev-webapp' 'pnpm 
start:sonataflow-dev-app'",
     "start:dev-webapp": "webpack serve --host 0.0.0.0 --env dev",
-    "start:sonataflow-dev-app": "npm --prefix 
./node_modules/@kie-tools/sonataflow-dev-app run start",
+    "start:sonataflow-dev-app": "CORS_DOMAIN=http://localhost:$(build-env 
sonataFlowDeploymentWebapp.dev.port) npm --prefix 
./node_modules/@kie-tools/sonataflow-dev-app run start",
     "test": "run-script-if --ignore-errors \"$(build-env 
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest 
--silent --verbose --passWithNoTests\""
   },
   "dependencies": {
diff --git a/packages/sonataflow-dev-app/README.md 
b/packages/sonataflow-dev-app/README.md
index f790b0594fe..537d63da162 100644
--- a/packages/sonataflow-dev-app/README.md
+++ b/packages/sonataflow-dev-app/README.md
@@ -27,18 +27,20 @@ The SonataFlow Dev App is intended for development purposes 
only. It provides mo
 
 To run the development app, use the following command:
 
-`pnpm start`
+`CORS_DOMAIN=https://localhost:8080 pnpm start`
 
 # Configuration
 
 The `SonataFlow Dev App` can be configured via environment variables:
 
-- _SONATAFLOW_DEV_APP_DELAY_: Defines the server's response delay in 
milliseconds
+- CORS_DOMAIN: (required) Defines the allowed origin for CORS, '\*' is not 
allowed.
+- SONATAFLOW_DEV_APP_DELAY: Defines the server's response delay in 
milliseconds.
 
 For example:
 
 ```bash
 $ export SONATAFLOW_DEV_APP_DELAY=500
+$ export CORS_DOMAIN=https://localhost:8080
 ```
 
 ### GraphQL Modifications
diff --git a/packages/sonataflow-dev-app/src/MockData/graphql.js 
b/packages/sonataflow-dev-app/src/MockData/graphql.js
index 42d2b323399..226ae19526a 100644
--- a/packages/sonataflow-dev-app/src/MockData/graphql.js
+++ b/packages/sonataflow-dev-app/src/MockData/graphql.js
@@ -45,7 +45,7 @@ module.exports = {
       endpoint: "http://localhost:4000/callback_state_timeouts";,
       serviceUrl: "http://localhost:4000";,
       source:
-        '{\n  "id": "callback_state_timeouts",\n  "version": "1.0",\n  "name": 
"Callback State Timeouts Example",\n  "description": "Simple process to show 
the callback state timeout working",\n  "start": "PrintStartMessage",\n  
"events": [\n    {\n      "name": "callbackEvent",\n      "source": "",\n      
"type": "callback_event_type"\n    }\n  ],\n  "functions": [\n    {\n      
"name": "systemOut",\n      "type": "custom",\n      "operation": "sysout"\n    
}\n  ],\n  "states": [\n    { [...]
+        '{\n  "id": "callback_state_timeouts",\n  "version": "1.0",\n  "name": 
"Callback State Timeouts Example",\n  "description": "Simple process to show 
the callback state timeout working",\n  "start": "PrintStartMessage",\n  
"events": [\n    {\n      "name": "callbackEvent",\n      "source": "",\n      
"type": "callback_event_type"\n    }\n  ],\n  "functions": [\n    {\n      
"name": "systemOut",\n      "type": "custom",\n      "operation": "sysout"\n    
}\n  ],\n  "states": [\n    { [...]
       error: null,
       childProcessInstances: [],
       nodes: [
diff --git a/packages/sonataflow-dev-app/src/config/index.js 
b/packages/sonataflow-dev-app/src/config/index.js
index 8fe1dc33c35..29ec5efae46 100644
--- a/packages/sonataflow-dev-app/src/config/index.js
+++ b/packages/sonataflow-dev-app/src/config/index.js
@@ -19,7 +19,7 @@
 const commonConfig = {
   env: process.env.NODE_ENV || "development",
   port: parseInt(process.env.PORT, 10) || 4000,
-  corsDomain: process.env.CORS_DOMAIN || "*",
+  corsDomain: process.env.CORS_DOMAIN,
 };
 
 module.exports = commonConfig;
diff --git a/packages/sonataflow-dev-app/src/server.js 
b/packages/sonataflow-dev-app/src/server.js
index cad9439830e..0690b9cc289 100644
--- a/packages/sonataflow-dev-app/src/server.js
+++ b/packages/sonataflow-dev-app/src/server.js
@@ -60,6 +60,15 @@ function listen() {
     console.log(`The server is running and listening at 
http://localhost:${port}`);
   });
 }
+
+// validate corsDomain, required for CodeQL scan
+if (!config.corsDomain) {
+  throw new Error("Invalid CORS_DOMAIN: Please specify a domain.");
+}
+if (config.corsDomain.trim() === "*") {
+  throw new Error('Invalid CORS_DOMAIN: wildcard "*" is not allowed.');
+}
+
 // parse application/x-www-form-urlencoded
 app.use(bodyParser.urlencoded({ extended: false }));
 
diff --git a/packages/sonataflow-management-console-webapp/package.json 
b/packages/sonataflow-management-console-webapp/package.json
index badcd382410..af39575481e 100644
--- a/packages/sonataflow-management-console-webapp/package.json
+++ b/packages/sonataflow-management-console-webapp/package.json
@@ -17,9 +17,9 @@
     "build:dev": "rimraf dist && webpack --env dev",
     "build:prod": "pnpm lint && pnpm test && rimraf dist && webpack",
     "lint": "run-script-if --bool \"$(build-env linters.run)\" --then 
\"kie-tools--eslint ./src\"",
-    "start": "concurrently 'pnpm start:dev-webapp' 'pnpm 
start:sonataflow-dev-app'",
+    "start": "concurrently --no-colors 'pnpm start:dev-webapp' 'pnpm 
start:sonataflow-dev-app'",
     "start:dev-webapp": "webpack serve --host 0.0.0.0 --env dev",
-    "start:sonataflow-dev-app": "npm --prefix 
./node_modules/@kie-tools/sonataflow-dev-app run start",
+    "start:sonataflow-dev-app": "CORS_DOMAIN=http://localhost:$(build-env 
sonataflowManagementConsoleWebapp.port) npm --prefix 
./node_modules/@kie-tools/sonataflow-dev-app run start",
     "test": "run-script-if --ignore-errors \"$(build-env 
tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest 
--silent --verbose --passWithNoTests\""
   },
   "dependencies": {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to