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

tbonelee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 76793932d5 [MINOR] Backport braces depth guard for React tooling 
(#5528)
76793932d5 is described below

commit 76793932d50779bd2543db97467f8c3398649f75
Author: YONGJAE LEE (이용재) <[email protected]>
AuthorDate: Sun Oct 11 16:17:01 2026 +0900

    [MINOR] Backport braces depth guard for React tooling (#5528)
---
 .github/workflows/frontend.yml                     |   5 +-
 .github/workflows/npm-audit-remediation.yml        |  37 +-
 .../projects/zeppelin-react/README.md              |  10 +-
 .../projects/zeppelin-react/audit-ci.jsonc         |  35 ++
 .../projects/zeppelin-react/package-lock.json      | 543 +++++++++++++++++++++
 .../projects/zeppelin-react/package.json           |   5 +
 .../zeppelin-react/patches/braces+3.0.3.patch      | 236 +++++++++
 .../zeppelin-react/scripts/check-braces-patch.cjs  |  46 ++
 8 files changed, 911 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml
index 37a4d1a438..4d00b10243 100644
--- a/.github/workflows/frontend.yml
+++ b/.github/workflows/frontend.yml
@@ -42,7 +42,10 @@ jobs:
       # TODO: Add zeppelin-web-angular root audit after Angular version 
upgrade and stabilization
       - name: Run npm audit on zeppelin-react
         working-directory: zeppelin-web-angular/projects/zeppelin-react
-        run: npm ci --ignore-scripts && npm audit --audit-level=high
+        run: |
+          npm ci --ignore-scripts --no-audit
+          npm run apply:patches
+          npm run audit
 
   run-playwright-e2e-tests:
     runs-on: ubuntu-24.04
diff --git a/.github/workflows/npm-audit-remediation.yml 
b/.github/workflows/npm-audit-remediation.yml
index 841bf3aab2..f66ad1b104 100644
--- a/.github/workflows/npm-audit-remediation.yml
+++ b/.github/workflows/npm-audit-remediation.yml
@@ -22,6 +22,11 @@ on:
   pull_request:
     paths:
       - '.github/workflows/npm-audit-remediation.yml'
+      - 'zeppelin-web-angular/projects/zeppelin-react/audit-ci.jsonc'
+      - 'zeppelin-web-angular/projects/zeppelin-react/patches/**'
+      - 
'zeppelin-web-angular/projects/zeppelin-react/scripts/check-braces-patch.cjs'
+      - 'zeppelin-web-angular/projects/zeppelin-react/package.json'
+      - 'zeppelin-web-angular/projects/zeppelin-react/package-lock.json'
 
 concurrency:
   group: npm-audit-remediation
@@ -61,6 +66,12 @@ jobs:
         with:
           node-version-file: 'zeppelin-web-angular/.nvmrc'
 
+      - name: Install and verify patched dependencies
+        working-directory: ${{ env.PACKAGE_DIRECTORY }}
+        run: |
+          npm ci --ignore-scripts --no-audit
+          npm run apply:patches
+
       - id: audit
         name: Check npm audit
         working-directory: ${{ env.PACKAGE_DIRECTORY }}
@@ -72,11 +83,16 @@ jobs:
           audit_status=$?
           set -e
 
-          if [[ ${audit_status} -eq 0 ]]; then
+          if npm run audit; then
             echo "needs_remediation=false" >> "${GITHUB_OUTPUT}"
             exit 0
           fi
 
+          if [[ ${audit_status} -eq 0 ]]; then
+            echo "::error::Audit policy failed without a reported 
vulnerability"
+            exit 1
+          fi
+
           vulnerable_count=$(node - "${RUNNER_TEMP}/npm-audit-before.json" 
<<'NODE'
           const fs = require('fs');
           const report = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
@@ -104,7 +120,19 @@ jobs:
       - name: Generate a lockfile-only fix
         if: steps.audit.outputs.needs_remediation == 'true'
         working-directory: ${{ env.PACKAGE_DIRECTORY }}
-        run: npm audit fix --package-lock-only --ignore-scripts 
--audit-level=high
+        shell: bash
+        run: |
+          # npm audit fix still exits nonzero while the locally patched braces
+          # release is reported as vulnerable. The policy gate below checks
+          # that every other high/critical finding was actually fixed.
+          set +e
+          npm audit fix --package-lock-only --ignore-scripts --audit-level=high
+          fix_status=$?
+          set -e
+          if [[ ${fix_status} -ne 0 ]] && git diff --quiet -- 
package-lock.json; then
+            echo "::error::npm audit fix failed without updating the lockfile"
+            exit "${fix_status}"
+          fi
 
       - name: Verify the generated diff
         if: steps.audit.outputs.needs_remediation == 'true'
@@ -128,7 +156,8 @@ jobs:
         working-directory: ${{ env.PACKAGE_DIRECTORY }}
         run: |
           npm ci --ignore-scripts --no-audit
-          npm audit --audit-level=high
+          npm run apply:patches
+          npm run audit
           npm run lint
           npm test
           npm run build
@@ -274,7 +303,7 @@ jobs:
             echo
             echo '- `npm ci --ignore-scripts --no-audit` in 
`zeppelin-web-angular`'
             echo '- `npm ci --ignore-scripts --no-audit` in 
`zeppelin-web-angular/projects/zeppelin-react`'
-            echo '- `npm audit --audit-level=high`'
+            echo '- `npm run apply:patches` and `npm run audit`'
             echo '- `npm run lint`'
             echo '- `npm test`'
             echo '- `npm run build`'
diff --git a/zeppelin-web-angular/projects/zeppelin-react/README.md 
b/zeppelin-web-angular/projects/zeppelin-react/README.md
index 9536a85420..2bf7fcd197 100644
--- a/zeppelin-web-angular/projects/zeppelin-react/README.md
+++ b/zeppelin-web-angular/projects/zeppelin-react/README.md
@@ -16,6 +16,15 @@ React micro-frontend that runs alongside the Angular host 
via [Webpack Module Fe
 
 - Design Document: [Micro Frontend Migration (Angular to React) 
Proposal](https://cwiki.apache.org/confluence/display/ZEPPELIN/Micro+Frontend+Migration%28Angular+to+React%29+Proposal)
 
+## Temporary braces security patch
+
+`[email protected]` has no published fix for 
[GHSA-vfj7-8cjw-p6xm](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm).
+`patches/braces+3.0.3.patch` backports the depth guards from 
[micromatch/braces#72](https://github.com/micromatch/braces/pull/72) at 
`28d440b5dd449dbf1fe6f3506cf94ecca4d02660`. The patch changes only the five 
affected `lib/` files in the published 3.0.3 package; it does not import 
unrelated unreleased changes on the upstream branch.
+
+Normal `npm ci` runs the `postinstall` patch and its regression check. When 
installing with `--ignore-scripts`, run `npm run apply:patches` explicitly 
before using the package. `npm run audit` retains the high-severity gate but 
temporarily permits only the two affected development-tool paths in 
`audit-ci.jsonc`, until 2026-12-04 00:00 UTC. The npm audit report still 
identifies 3.0.3 as vulnerable because it cannot inspect local patches.
+
+After upstream publishes a fixed version, update the lockfile, remove the 
patch and audit exceptions, and restore the unmodified audit command.
+
 ## React mount infrastructure (Angular side)
 
 The Angular host's `src/app/share/react-mount/` exports two pieces:
@@ -166,4 +175,3 @@ export function mount(element: HTMLElement, props: Props): 
ReactMountHandle;
    an inline object literal) so identity is stable when nothing changed.
 
 Every exposed module must return the handle contract from `mount`. The 
directive assigns the return value straight to its handle, so returning a bare 
unmount function makes the next prop change throw.
-
diff --git a/zeppelin-web-angular/projects/zeppelin-react/audit-ci.jsonc 
b/zeppelin-web-angular/projects/zeppelin-react/audit-ci.jsonc
new file mode 100644
index 0000000000..4072cb472e
--- /dev/null
+++ b/zeppelin-web-angular/projects/zeppelin-react/audit-ci.jsonc
@@ -0,0 +1,35 @@
+// 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.
+
+{
+  "high": true,
+  "report-type": "summary",
+  "allowlist": [
+    {
+      
"GHSA-vfj7-8cjw-p6xm|patch-package>find-yarn-workspace-root>micromatch>braces": 
{
+        "active": true,
+        "notes": "braces 3.0.3 is patched locally from micromatch/braces#72; 
remove after a fixed release",
+        "expiry": "2026-12-04"
+      }
+    },
+    {
+      
"GHSA-vfj7-8cjw-p6xm|webpack-dev-server>http-proxy-middleware>micromatch>braces":
 {
+        "active": true,
+        "notes": "braces 3.0.3 is patched locally from micromatch/braces#72; 
remove after a fixed release",
+        "expiry": "2026-12-04"
+      }
+    }
+  ]
+}
diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json 
b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json
index 81f23343ec..e7fdc495d4 100644
--- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json
+++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json
@@ -34,6 +34,7 @@
         "@typescript-eslint/parser": "^8.56.1",
         "@vitest/coverage-v8": "4.1.11",
         "@vitest/eslint-plugin": "^1.6.27",
+        "audit-ci": "7.1.0",
         "css-loader": "6.8.0",
         "eslint": "^9.28.0",
         "eslint-plugin-react": "^7.37.5",
@@ -41,6 +42,7 @@
         "globals": "^15.14.0",
         "html-webpack-plugin": "5.5.0",
         "jsdom": "29.1.1",
+        "patch-package": "8.0.1",
         "style-loader": "3.3.0",
         "ts-loader": "9.6.2",
         "typescript": "5.9.3",
@@ -2706,6 +2708,13 @@
       "dev": true,
       "license": "Apache-2.0"
     },
+    "node_modules/@yarnpkg/lockfile": {
+      "version": "1.1.0",
+      "resolved": 
"https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz";,
+      "integrity": 
"sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
+      "dev": true,
+      "license": "BSD-2-Clause"
+    },
     "node_modules/@zeppelin/notebook-core": {
       "resolved": "../zeppelin-notebook-core",
       "link": true
@@ -3190,6 +3199,30 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/audit-ci": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/audit-ci/-/audit-ci-7.1.0.tgz";,
+      "integrity": 
"sha512-PjjEejlST57S/aDbeWLic0glJ8CNl/ekY3kfGFPMrPkmuaYaDKcMH0F9x9yS9Vp6URhuefSCubl/G0Y2r6oP0g==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "escape-string-regexp": "^4.0.0",
+        "event-stream": "4.0.1",
+        "jju": "^1.4.0",
+        "jsonstream-next": "^3.0.0",
+        "readline-transform": "1.0.0",
+        "semver": "^7.0.0",
+        "tslib": "^2.0.0",
+        "yargs": "^17.0.0"
+      },
+      "bin": {
+        "audit-ci": "dist/bin.js"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
     "node_modules/available-typed-arrays": {
       "version": "1.0.7",
       "resolved": 
"https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz";,
@@ -3585,6 +3618,22 @@
         "node": ">=6.0"
       }
     },
+    "node_modules/ci-info": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz";,
+      "integrity": 
"sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/sibiraj-s";
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/classnames": {
       "version": "2.5.1",
       "resolved": 
"https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz";,
@@ -3604,6 +3653,21 @@
         "node": ">= 10.0"
       }
     },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz";,
+      "integrity": 
"sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/clone-deep": {
       "version": "4.0.1",
       "resolved": 
"https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz";,
@@ -4283,6 +4347,13 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/duplexer": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz";,
+      "integrity": 
"sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz";,
@@ -4297,6 +4368,13 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": 
"https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz";,
+      "integrity": 
"sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/encodeurl": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz";,
@@ -4827,6 +4905,22 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/event-stream": {
+      "version": "4.0.1",
+      "resolved": 
"https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz";,
+      "integrity": 
"sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "duplexer": "^0.1.1",
+        "from": "^0.1.7",
+        "map-stream": "0.0.7",
+        "pause-stream": "^0.0.11",
+        "split": "^1.0.1",
+        "stream-combiner": "^0.2.2",
+        "through": "^2.3.8"
+      }
+    },
     "node_modules/events": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz";,
@@ -5094,6 +5188,16 @@
         "url": "https://github.com/sponsors/sindresorhus";
       }
     },
+    "node_modules/find-yarn-workspace-root": {
+      "version": "2.0.0",
+      "resolved": 
"https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz";,
+      "integrity": 
"sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "micromatch": "^4.0.2"
+      }
+    },
     "node_modules/flat": {
       "version": "5.0.2",
       "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz";,
@@ -5170,6 +5274,28 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/from": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz";,
+      "integrity": 
"sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fs-extra": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz";,
+      "integrity": 
"sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/fsevents": {
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz";,
@@ -5236,6 +5362,16 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": 
"https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz";,
+      "integrity": 
"sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
     "node_modules/get-intrinsic": {
       "version": "1.3.0",
       "resolved": 
"https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz";,
@@ -5950,6 +6086,16 @@
         "url": "https://github.com/sponsors/ljharb";
       }
     },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": 
"https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz";,
+      "integrity": 
"sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/is-generator-function": {
       "version": "1.1.2",
       "resolved": 
"https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz";,
@@ -6394,6 +6540,13 @@
         "url": "https://github.com/chalk/supports-color?sponsor=1";
       }
     },
+    "node_modules/jju": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz";,
+      "integrity": 
"sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz";,
@@ -6485,6 +6638,26 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/json-stable-stringify": {
+      "version": "1.3.0",
+      "resolved": 
"https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz";,
+      "integrity": 
"sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind": "^1.0.8",
+        "call-bound": "^1.0.4",
+        "isarray": "^2.0.5",
+        "jsonify": "^0.0.1",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb";
+      }
+    },
     "node_modules/json-stable-stringify-without-jsonify": {
       "version": "1.0.1",
       "resolved": 
"https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz";,
@@ -6501,6 +6674,56 @@
         "string-convert": "^0.2.0"
       }
     },
+    "node_modules/jsonfile": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz";,
+      "integrity": 
"sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/jsonify": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz";,
+      "integrity": 
"sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==",
+      "dev": true,
+      "license": "Public Domain",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb";
+      }
+    },
+    "node_modules/jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz";,
+      "integrity": 
"sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+      "dev": true,
+      "engines": [
+        "node >= 0.2.0"
+      ],
+      "license": "MIT"
+    },
+    "node_modules/jsonstream-next": {
+      "version": "3.0.0",
+      "resolved": 
"https://registry.npmjs.org/jsonstream-next/-/jsonstream-next-3.0.0.tgz";,
+      "integrity": 
"sha512-aAi6oPhdt7BKyQn1SrIIGZBt0ukKuOUE1qV6kJ3GgioSOYzsRc8z9Hfr1BVmacA/jLe9nARfmgMGgn68BqIAgg==",
+      "dev": true,
+      "license": "(MIT OR Apache-2.0)",
+      "dependencies": {
+        "jsonparse": "^1.2.0",
+        "through2": "^4.0.2"
+      },
+      "bin": {
+        "jsonstream-next": "bin.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/jsx-ast-utils": {
       "version": "3.3.5",
       "resolved": 
"https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz";,
@@ -6537,6 +6760,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/klaw-sync": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz";,
+      "integrity": 
"sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.1.11"
+      }
+    },
     "node_modules/launch-editor": {
       "version": "2.14.1",
       "resolved": 
"https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz";,
@@ -6947,6 +7180,13 @@
         "url": "https://github.com/sponsors/sindresorhus";
       }
     },
+    "node_modules/map-stream": {
+      "version": "0.0.7",
+      "resolved": 
"https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz";,
+      "integrity": 
"sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/math-intrinsics": {
       "version": "1.1.0",
       "resolved": 
"https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz";,
@@ -7087,6 +7327,16 @@
         "url": "https://github.com/sponsors/isaacs";
       }
     },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz";,
+      "integrity": 
"sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb";
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz";,
@@ -7539,6 +7789,82 @@
         "tslib": "^2.0.3"
       }
     },
+    "node_modules/patch-package": {
+      "version": "8.0.1",
+      "resolved": 
"https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz";,
+      "integrity": 
"sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@yarnpkg/lockfile": "^1.1.0",
+        "chalk": "^4.1.2",
+        "ci-info": "^3.7.0",
+        "cross-spawn": "^7.0.3",
+        "find-yarn-workspace-root": "^2.0.0",
+        "fs-extra": "^10.0.0",
+        "json-stable-stringify": "^1.0.2",
+        "klaw-sync": "^6.0.0",
+        "minimist": "^1.2.6",
+        "open": "^7.4.2",
+        "semver": "^7.5.3",
+        "slash": "^2.0.0",
+        "tmp": "^0.2.4",
+        "yaml": "^2.2.2"
+      },
+      "bin": {
+        "patch-package": "index.js"
+      },
+      "engines": {
+        "node": ">=14",
+        "npm": ">5"
+      }
+    },
+    "node_modules/patch-package/node_modules/is-docker": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz";,
+      "integrity": 
"sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus";
+      }
+    },
+    "node_modules/patch-package/node_modules/is-wsl": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz";,
+      "integrity": 
"sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-docker": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/patch-package/node_modules/open": {
+      "version": "7.4.2",
+      "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz";,
+      "integrity": 
"sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-docker": "^2.0.0",
+        "is-wsl": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus";
+      }
+    },
     "node_modules/path-exists": {
       "version": "4.0.0",
       "resolved": 
"https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz";,
@@ -7584,6 +7910,19 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/pause-stream": {
+      "version": "0.0.11",
+      "resolved": 
"https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz";,
+      "integrity": 
"sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+      "dev": true,
+      "license": [
+        "MIT",
+        "Apache2"
+      ],
+      "dependencies": {
+        "through": "~2.3"
+      }
+    },
     "node_modules/picocolors": {
       "version": "1.1.1",
       "resolved": 
"https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz";,
@@ -8665,6 +9004,21 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": 
"https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz";,
+      "integrity": 
"sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/readdirp": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz";,
@@ -8679,6 +9033,16 @@
         "url": "https://paulmillr.com/funding/";
       }
     },
+    "node_modules/readline-transform": {
+      "version": "1.0.0",
+      "resolved": 
"https://registry.npmjs.org/readline-transform/-/readline-transform-1.0.0.tgz";,
+      "integrity": 
"sha512-7KA6+N9IGat52d83dvxnApAWN+MtVb1MiVuMR/cf1O4kYsJG+g/Aav0AHcHKsb6StinayfPLne0+fMX2sOzAKg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/rechoir": {
       "version": "0.8.0",
       "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz";,
@@ -8789,6 +9153,16 @@
         "strip-ansi": "^6.0.1"
       }
     },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": 
"https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz";,
+      "integrity": 
"sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/require-from-string": {
       "version": "2.0.2",
       "resolved": 
"https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz";,
@@ -9472,6 +9846,16 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/slash": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz";,
+      "integrity": 
"sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/source-map": {
       "version": "0.6.1",
       "resolved": 
"https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz";,
@@ -9503,6 +9887,19 @@
         "source-map": "^0.6.0"
       }
     },
+    "node_modules/split": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz";,
+      "integrity": 
"sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "through": "2"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/ssf": {
       "version": "0.11.2",
       "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz";,
@@ -9553,12 +9950,48 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/stream-combiner": {
+      "version": "0.2.2",
+      "resolved": 
"https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz";,
+      "integrity": 
"sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "duplexer": "~0.1.1",
+        "through": "~2.3.4"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": 
"https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz";,
+      "integrity": 
"sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
     "node_modules/string-convert": {
       "version": "0.2.1",
       "resolved": 
"https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz";,
       "integrity": 
"sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==",
       "license": "MIT"
     },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": 
"https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz";,
+      "integrity": 
"sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/string.prototype.matchall": {
       "version": "4.0.12",
       "resolved": 
"https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz";,
@@ -9866,6 +10299,23 @@
         "node": ">=12.22"
       }
     },
+    "node_modules/through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz";,
+      "integrity": 
"sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/through2": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz";,
+      "integrity": 
"sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readable-stream": "3"
+      }
+    },
     "node_modules/thunky": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz";,
@@ -9937,6 +10387,16 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/tmp": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz";,
+      "integrity": 
"sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
     "node_modules/to-regex-range": {
       "version": "5.0.1",
       "resolved": 
"https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz";,
@@ -10308,6 +10768,16 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/universalify": {
+      "version": "2.0.1",
+      "resolved": 
"https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz";,
+      "integrity": 
"sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
     "node_modules/unpipe": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz";,
@@ -11062,6 +11532,24 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz";,
+      "integrity": 
"sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1";
+      }
+    },
     "node_modules/wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz";,
@@ -11155,6 +11643,61 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz";,
+      "integrity": 
"sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yaml": {
+      "version": "2.9.1",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz";,
+      "integrity": 
"sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==",
+      "dev": true,
+      "license": "ISC",
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/eemeli";
+      }
+    },
+    "node_modules/yargs": {
+      "version": "17.7.3",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz";,
+      "integrity": 
"sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": 
"https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz";,
+      "integrity": 
"sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/yocto-queue": {
       "version": "0.1.0",
       "resolved": 
"https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz";,
diff --git a/zeppelin-web-angular/projects/zeppelin-react/package.json 
b/zeppelin-web-angular/projects/zeppelin-react/package.json
index 191cc6cfef..783b6193a8 100644
--- a/zeppelin-web-angular/projects/zeppelin-react/package.json
+++ b/zeppelin-web-angular/projects/zeppelin-react/package.json
@@ -5,6 +5,9 @@
     "*.css"
   ],
   "scripts": {
+    "postinstall": "npm run apply:patches",
+    "apply:patches": "patch-package && node scripts/check-braces-patch.cjs",
+    "audit": "node scripts/check-braces-patch.cjs && audit-ci --config 
audit-ci.jsonc",
     "start": "webpack serve --config webpack.config.js --mode development",
     "build": "webpack --config webpack.config.js --mode production",
     "dev": "webpack serve --config webpack.config.js --mode development",
@@ -41,6 +44,7 @@
     "@typescript-eslint/parser": "^8.56.1",
     "@vitest/coverage-v8": "4.1.11",
     "@vitest/eslint-plugin": "^1.6.27",
+    "audit-ci": "7.1.0",
     "css-loader": "6.8.0",
     "eslint": "^9.28.0",
     "eslint-plugin-react": "^7.37.5",
@@ -48,6 +52,7 @@
     "globals": "^15.14.0",
     "html-webpack-plugin": "5.5.0",
     "jsdom": "29.1.1",
+    "patch-package": "8.0.1",
     "style-loader": "3.3.0",
     "ts-loader": "9.6.2",
     "typescript": "5.9.3",
diff --git 
a/zeppelin-web-angular/projects/zeppelin-react/patches/braces+3.0.3.patch 
b/zeppelin-web-angular/projects/zeppelin-react/patches/braces+3.0.3.patch
new file mode 100644
index 0000000000..809532547e
--- /dev/null
+++ b/zeppelin-web-angular/projects/zeppelin-react/patches/braces+3.0.3.patch
@@ -0,0 +1,236 @@
+diff --git a/node_modules/braces/lib/compile.js 
b/node_modules/braces/lib/compile.js
+index dce69be..945a78b 100644
+--- a/node_modules/braces/lib/compile.js
++++ b/node_modules/braces/lib/compile.js
+@@ -2,9 +2,15 @@
+ 
+ const fill = require('fill-range');
+ const utils = require('./utils');
++const { MAX_DEPTH } = require('./constants');
+ 
+ const compile = (ast, options = {}) => {
+-  const walk = (node, parent = {}) => {
++  const maxDepth = Number.isFinite(options.maxDepth) ? Math.min(MAX_DEPTH, 
options.maxDepth) : MAX_DEPTH;
++
++  const walk = (node, parent = {}, depth = 0) => {
++    if (node.nodes && depth > maxDepth) {
++      throw new RangeError(`AST depth (${depth}), exceeds max depth 
(${maxDepth})`);
++    }
+     const invalidBlock = utils.isInvalidBrace(parent);
+     const invalidNode = node.invalid === true && options.escapeInvalid === 
true;
+     const invalid = invalidBlock === true || invalidNode === true;
+@@ -47,14 +53,14 @@ const compile = (ast, options = {}) => {
+ 
+     if (node.nodes) {
+       for (const child of node.nodes) {
+-        output += walk(child, node);
++        output += walk(child, node, child.nodes ? depth + 1 : depth);
+       }
+     }
+ 
+     return output;
+   };
+ 
+-  return walk(ast);
++  return walk(ast, {}, ast.type === 'root' ? 0 : 1);
+ };
+ 
+ module.exports = compile;
+diff --git a/node_modules/braces/lib/constants.js 
b/node_modules/braces/lib/constants.js
+index 2bb3b88..c237099 100644
+--- a/node_modules/braces/lib/constants.js
++++ b/node_modules/braces/lib/constants.js
+@@ -1,6 +1,7 @@
+ 'use strict';
+ 
+ module.exports = {
++  MAX_DEPTH: 100,
+   MAX_LENGTH: 10000,
+ 
+   // Digits
+diff --git a/node_modules/braces/lib/expand.js 
b/node_modules/braces/lib/expand.js
+index 35b2c41..8211c5b 100644
+--- a/node_modules/braces/lib/expand.js
++++ b/node_modules/braces/lib/expand.js
+@@ -3,6 +3,7 @@
+ const fill = require('fill-range');
+ const stringify = require('./stringify');
+ const utils = require('./utils');
++const { MAX_DEPTH } = require('./constants');
+ 
+ const append = (queue = '', stash = '', enclose = false) => {
+   const result = [];
+@@ -30,19 +31,31 @@ const append = (queue = '', stash = '', enclose = false) 
=> {
+   return utils.flatten(result);
+ };
+ 
++const queueOwner = node => {
++  if (node.type === 'brace' || node.type === 'root' || !node.parent) return 
node;
++
++  const seen = new Set();
++  while (node.type !== 'brace' && node.type !== 'root' && node.parent) {
++    if (seen.has(node)) {
++      throw new RangeError('AST parent chain contains a cycle');
++    }
++    seen.add(node);
++    node = node.parent;
++  }
++  return node;
++};
++
+ const expand = (ast, options = {}) => {
+   const rangeLimit = options.rangeLimit === undefined ? 1000 : 
options.rangeLimit;
++  const maxDepth = Number.isFinite(options.maxDepth) ? Math.min(MAX_DEPTH, 
options.maxDepth) : MAX_DEPTH;
+ 
+-  const walk = (node, parent = {}) => {
++  const walk = (node, parent = {}, depth = 0) => {
++    if (node.nodes && depth > maxDepth) {
++      throw new RangeError(`AST depth (${depth}), exceeds max depth 
(${maxDepth})`);
++    }
+     node.queue = [];
+ 
+-    let p = parent;
+-    let q = parent.queue;
+-
+-    while (p.type !== 'brace' && p.type !== 'root' && p.parent) {
+-      p = p.parent;
+-      q = p.queue;
+-    }
++    const q = queueOwner(parent).queue;
+ 
+     if (node.invalid || node.dollar) {
+       q.push(append(q.pop(), stringify(node, options)));
+@@ -72,13 +85,7 @@ const expand = (ast, options = {}) => {
+     }
+ 
+     const enclose = utils.encloseBrace(node);
+-    let queue = node.queue;
+-    let block = node;
+-
+-    while (block.type !== 'brace' && block.type !== 'root' && block.parent) {
+-      block = block.parent;
+-      queue = block.queue;
+-    }
++    const queue = queueOwner(node).queue;
+ 
+     for (let i = 0; i < node.nodes.length; i++) {
+       const child = node.nodes[i];
+@@ -100,14 +107,14 @@ const expand = (ast, options = {}) => {
+       }
+ 
+       if (child.nodes) {
+-        walk(child, node);
++        walk(child, node, child.nodes ? depth + 1 : depth);
+       }
+     }
+ 
+     return queue;
+   };
+ 
+-  return utils.flatten(walk(ast));
++  return utils.flatten(walk(ast, {}, ast.type === 'root' ? 0 : 1));
+ };
+ 
+ module.exports = expand;
+diff --git a/node_modules/braces/lib/parse.js 
b/node_modules/braces/lib/parse.js
+index 3a6988e..d4c2c72 100644
+--- a/node_modules/braces/lib/parse.js
++++ b/node_modules/braces/lib/parse.js
+@@ -7,6 +7,7 @@ const stringify = require('./stringify');
+  */
+ 
+ const {
++  MAX_DEPTH,
+   MAX_LENGTH,
+   CHAR_BACKSLASH, /* \ */
+   CHAR_BACKTICK, /* ` */
+@@ -35,6 +36,7 @@ const parse = (input, options = {}) => {
+ 
+   const opts = options || {};
+   const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, 
opts.maxLength) : MAX_LENGTH;
++  const maxDepth = Number.isFinite(opts.maxDepth) ? Math.min(MAX_DEPTH, 
opts.maxDepth) : MAX_DEPTH;
+   if (input.length > max) {
+     throw new SyntaxError(`Input length (${input.length}), exceeds max 
characters (${max})`);
+   }
+@@ -47,6 +49,7 @@ const parse = (input, options = {}) => {
+   const length = input.length;
+   let index = 0;
+   let depth = 0;
++  let nesting = 0;
+   let value;
+ 
+   /**
+@@ -143,6 +146,10 @@ const parse = (input, options = {}) => {
+      */
+ 
+     if (value === CHAR_LEFT_PARENTHESES) {
++      if (nesting + 1 > maxDepth) {
++        throw new SyntaxError(`Input depth (${nesting + 1}), exceeds max 
depth (${maxDepth})`);
++      }
++      nesting++;
+       block = push({ type: 'paren', nodes: [] });
+       stack.push(block);
+       push({ type: 'text', value });
+@@ -156,6 +163,7 @@ const parse = (input, options = {}) => {
+       }
+       block = stack.pop();
+       push({ type: 'text', value });
++      nesting--;
+       block = stack[stack.length - 1];
+       continue;
+     }
+@@ -195,6 +203,10 @@ const parse = (input, options = {}) => {
+      */
+ 
+     if (value === CHAR_LEFT_CURLY_BRACE) {
++      if (nesting + 1 > maxDepth) {
++        throw new SyntaxError(`Input depth (${nesting + 1}), exceeds max 
depth (${maxDepth})`);
++      }
++      nesting++;
+       depth++;
+ 
+       const dollar = prev.value && prev.value.slice(-1) === '$' || 
block.dollar === true;
+@@ -231,6 +243,7 @@ const parse = (input, options = {}) => {
+ 
+       push({ type, value });
+       depth--;
++      nesting--;
+ 
+       block = stack[stack.length - 1];
+       continue;
+diff --git a/node_modules/braces/lib/stringify.js 
b/node_modules/braces/lib/stringify.js
+index 8bcf872..651849c 100644
+--- a/node_modules/braces/lib/stringify.js
++++ b/node_modules/braces/lib/stringify.js
+@@ -1,9 +1,15 @@
+ 'use strict';
+ 
+ const utils = require('./utils');
++const { MAX_DEPTH } = require('./constants');
+ 
+ module.exports = (ast, options = {}) => {
+-  const stringify = (node, parent = {}) => {
++  const maxDepth = Number.isFinite(options.maxDepth) ? Math.min(MAX_DEPTH, 
options.maxDepth) : MAX_DEPTH;
++
++  const stringify = (node, parent = {}, depth = 0) => {
++    if (node.nodes && depth > maxDepth) {
++      throw new RangeError(`AST depth (${depth}), exceeds max depth 
(${maxDepth})`);
++    }
+     const invalidBlock = options.escapeInvalid && 
utils.isInvalidBrace(parent);
+     const invalidNode = node.invalid === true && options.escapeInvalid === 
true;
+     let output = '';
+@@ -21,12 +27,11 @@ module.exports = (ast, options = {}) => {
+ 
+     if (node.nodes) {
+       for (const child of node.nodes) {
+-        output += stringify(child);
++        output += stringify(child, undefined, child.nodes ? depth + 1 : 
depth);
+       }
+     }
+     return output;
+   };
+ 
+-  return stringify(ast);
++  return stringify(ast, {}, ast.type === 'root' ? 0 : 1);
+ };
+-
diff --git 
a/zeppelin-web-angular/projects/zeppelin-react/scripts/check-braces-patch.cjs 
b/zeppelin-web-angular/projects/zeppelin-react/scripts/check-braces-patch.cjs
new file mode 100644
index 0000000000..22a9dbcc9f
--- /dev/null
+++ 
b/zeppelin-web-angular/projects/zeppelin-react/scripts/check-braces-patch.cjs
@@ -0,0 +1,46 @@
+// 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.
+
+'use strict';
+
+const assert = require('node:assert/strict');
+const braces = require('braces');
+
+assert.equal(require('braces/package.json').version, '3.0.3');
+
+const nested = depth => '{'.repeat(depth) + 'a' + '}'.repeat(depth);
+const boundary = braces.parse(nested(100));
+assert.doesNotThrow(() => braces.compile(boundary));
+assert.doesNotThrow(() => braces.expand(braces.parse(nested(100))));
+assert.doesNotThrow(() => braces.stringify(boundary));
+assert.throws(() => braces.parse(nested(101)), /exceeds max depth \(100\)/);
+assert.doesNotThrow(() => braces.parse('('.repeat(100) + 'a' + 
')'.repeat(100)));
+assert.throws(() => braces.parse('('.repeat(101) + 'a' + ')'.repeat(101)), 
/exceeds max depth \(100\)/);
+assert.throws(() => braces.parse('{{a,b},c}', { maxDepth: 1.5 }), /exceeds max 
depth \(1.5\)/);
+
+const deepAst = () => {
+  let node = { type: 'text', value: 'a' };
+  for (let depth = 0; depth < 101; depth++) {
+    node = { type: 'brace', open: true, close: true, nodes: [node] };
+  }
+  return node;
+};
+
+for (const method of ['compile', 'expand', 'stringify']) {
+  assert.throws(() => braces[method](deepAst()), /exceeds max depth \(100\)/, 
method);
+}
+
+assert.equal(braces.stringify(braces.parse('{{a}}'), { escapeInvalid: true }), 
'{{a}}');
+console.log('braces depth patch verified');

Reply via email to