From 228e5745d77e20c6ea67a5c48acafd718207f4cd Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Thu, 22 Jan 2026 06:17:26 +1100 Subject: [PATCH] fix(security): address multiple security vulnerabilities This commit bundles fixes for several security issues identified by GitHub Advanced Security and Semgrep code scanning. ## Workflow Permissions (CodeQL) - Add explicit permissions blocks to GitHub Actions workflows - Restrict GITHUB_TOKEN to minimum required permissions - Affected files: automated-releases.yml, build-and-test-v3.yml, publish-npm.yml, test-simple.yml ## Path Traversal (CodeQL) - Fix directory traversal vulnerability in screen example - Add path validation using filepath.Clean and containment checks - Affected file: v3/examples/screen/main.go ## Rollup XSS Vulnerability (Semgrep) - Update rollup from 3.28.0 to 3.29.5 - Fixes CVE-2024-47068 (Cross-site Scripting) - Affected file: v3/examples/dev/frontend/package-lock.json Note: The setup wizard command injection alert was reviewed and determined to be a false positive - commands originate from backend package manager detection, not user input. Added clarifying documentation. Co-Authored-By: Claude Opus 4.5 --- .github/workflows/automated-releases.yml | 15 +- .github/workflows/build-and-test-v3.yml | 13 ++ .github/workflows/publish-npm.yml | 6 + .github/workflows/test-simple.yml | 4 + v3/UNRELEASED_CHANGELOG.md | 3 + v3/examples/dev/frontend/package-lock.json | 155 +++++++++++++-------- v3/examples/screen/main.go | 19 ++- v3/internal/setupwizard/wizard.go | 11 +- 8 files changed, 163 insertions(+), 63 deletions(-) diff --git a/.github/workflows/automated-releases.yml b/.github/workflows/automated-releases.yml index 83445d869..934643d70 100644 --- a/.github/workflows/automated-releases.yml +++ b/.github/workflows/automated-releases.yml @@ -20,6 +20,10 @@ on: env: GO_VERSION: '1.24' +# Restrict default GITHUB_TOKEN permissions +permissions: + contents: read + jobs: check-permissions: name: Check Release Permissions @@ -45,6 +49,8 @@ jobs: detect-v2-changes: name: Detect v2 Changes runs-on: ubuntu-latest + permissions: + contents: read needs: check-permissions if: needs.check-permissions.outputs.authorized == 'true' outputs: @@ -90,8 +96,10 @@ jobs: fi detect-v3-changes: - name: Detect v3-alpha Changes + name: Detect v3-alpha Changes runs-on: ubuntu-latest + permissions: + contents: read needs: check-permissions if: needs.check-permissions.outputs.authorized == 'true' outputs: @@ -140,6 +148,8 @@ jobs: release-v2: name: Create v2 Release runs-on: ubuntu-latest + permissions: + contents: write needs: [check-permissions, detect-v2-changes] if: | needs.check-permissions.outputs.authorized == 'true' && @@ -232,6 +242,8 @@ jobs: release-v3: name: Create v3-alpha Release runs-on: ubuntu-latest + permissions: + contents: write needs: [check-permissions, detect-v3-changes] if: | needs.check-permissions.outputs.authorized == 'true' && @@ -326,6 +338,7 @@ jobs: summary: name: Release Summary runs-on: ubuntu-latest + permissions: {} needs: [check-permissions, detect-v2-changes, detect-v3-changes, release-v2, release-v3] if: always() && needs.check-permissions.outputs.authorized == 'true' steps: diff --git a/.github/workflows/build-and-test-v3.yml b/.github/workflows/build-and-test-v3.yml index cae6b3556..7045e89c8 100644 --- a/.github/workflows/build-and-test-v3.yml +++ b/.github/workflows/build-and-test-v3.yml @@ -10,10 +10,15 @@ on: branches: - v3-alpha +# Restrict default GITHUB_TOKEN permissions +permissions: + contents: read + jobs: check_approval: name: Check PR Approval runs-on: ubuntu-latest + permissions: {} if: github.base_ref == 'v3-alpha' outputs: approved: ${{ steps.check.outputs.approved }} @@ -31,6 +36,8 @@ jobs: name: Run JS Tests needs: check_approval runs-on: ubuntu-latest + permissions: + contents: read if: github.base_ref == 'v3-alpha' strategy: matrix: @@ -100,6 +107,8 @@ jobs: name: Run Go Tests v3 needs: [check_approval, test_js] runs-on: ${{ matrix.os }} + permissions: + contents: read if: github.base_ref == 'v3-alpha' strategy: fail-fast: false @@ -175,6 +184,7 @@ jobs: if: always() needs: [test_js, test_go, test_templates] runs-on: ubuntu-latest + permissions: {} steps: - uses: geekyeggo/delete-artifact@v5 with: @@ -187,6 +197,8 @@ jobs: name: Test Templates needs: [test_js, test_go] runs-on: ${{ matrix.os }} + permissions: + contents: read if: github.base_ref == 'v3-alpha' strategy: fail-fast: false @@ -263,6 +275,7 @@ jobs: build_results: if: ${{ always() }} runs-on: ubuntu-latest + permissions: {} name: v3 Build Results needs: [test_go, test_js, test_templates] steps: diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 3ebd2f282..25d5f2e6f 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -3,6 +3,10 @@ on: branches: ['v3-alpha'] workflow_dispatch: +# Restrict default GITHUB_TOKEN permissions +permissions: + contents: read + concurrency: group: publish-npm-v3 cancel-in-progress: true @@ -11,6 +15,8 @@ jobs: detect: name: Detect committed changes if: github.event_name != 'workflow_dispatch' + permissions: + contents: read outputs: changed: ${{ steps.package-json-changes.outputs.any_modified == 'true' || steps.source-changes.outputs.any_modified == 'true' }} runs-on: ubuntu-latest diff --git a/.github/workflows/test-simple.yml b/.github/workflows/test-simple.yml index 8c4c88295..ca4e4f21d 100644 --- a/.github/workflows/test-simple.yml +++ b/.github/workflows/test-simple.yml @@ -3,9 +3,13 @@ name: Test Simple on: workflow_dispatch: +# Restrict default GITHUB_TOKEN permissions +permissions: {} + jobs: test: runs-on: ubuntu-latest + permissions: {} steps: - name: Test run: echo "Hello World" \ No newline at end of file diff --git a/v3/UNRELEASED_CHANGELOG.md b/v3/UNRELEASED_CHANGELOG.md index af0097c53..6c236fc61 100644 --- a/v3/UNRELEASED_CHANGELOG.md +++ b/v3/UNRELEASED_CHANGELOG.md @@ -33,6 +33,9 @@ After processing, the content will be moved to the main changelog and this file ## Security +- Restrict GITHUB_TOKEN permissions in workflow files to follow principle of least privilege +- Fix path traversal vulnerability in screen example asset middleware +- Update rollup to 3.29.5 to fix XSS vulnerability (CVE-2024-47068) --- diff --git a/v3/examples/dev/frontend/package-lock.json b/v3/examples/dev/frontend/package-lock.json index 309115bf9..7a92cee3a 100644 --- a/v3/examples/dev/frontend/package-lock.json +++ b/v3/examples/dev/frontend/package-lock.json @@ -21,6 +21,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -37,6 +38,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -53,6 +55,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -69,6 +72,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -85,6 +89,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -101,6 +106,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -117,6 +123,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -133,6 +140,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -149,6 +157,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -165,6 +174,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -181,6 +191,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -197,6 +208,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -213,6 +225,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -229,6 +242,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -245,6 +259,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -261,6 +276,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -277,6 +293,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -293,6 +310,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -309,6 +327,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -325,6 +344,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -341,6 +361,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -357,6 +378,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -366,22 +388,25 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.5.tgz", - "integrity": "sha512-UJKsFNwhzCVuiZd06jM/psscyNJNDwjQC+qIeb7GBJK9iWeQCcIyfcPWDvbCudfcJggY9jtxJeeaZH7uny93FQ==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.5.3.tgz", + "integrity": "sha512-erhNtXxE5/6xGZz/M9eXsmI7Pxa6MS7jyTy06zN3Ck++ldrppOnOlJwHHTsMC7DHDQdgUp4NAc4cDNQ9eGdB/w==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^1.0.3", + "@sveltejs/vite-plugin-svelte-inspector": "^1.0.4", "debug": "^4.3.4", "deepmerge": "^4.3.1", "kleur": "^4.1.5", - "magic-string": "^0.30.2", + "magic-string": "^0.30.3", "svelte-hmr": "^0.15.3", "vitefu": "^0.2.4" }, @@ -389,15 +414,16 @@ "node": "^14.18.0 || >= 16" }, "peerDependencies": { - "svelte": "^3.54.0 || ^4.0.0", + "svelte": "^3.54.0 || ^4.0.0 || ^5.0.0-next.0", "vite": "^4.0.0" } }, "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.3.tgz", - "integrity": "sha512-Khdl5jmmPN6SUsVuqSXatKpQTMIifoQPDanaxC84m9JxIibWvSABJyHpyys0Z+1yYrxY5TTEQm+6elh0XCMaOA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz", + "integrity": "sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -411,12 +437,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -432,6 +459,7 @@ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -442,6 +470,7 @@ "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -474,11 +503,12 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -492,32 +522,32 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -525,6 +555,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -533,15 +564,16 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -557,20 +589,22 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/rollup": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", - "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -583,10 +617,11 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -596,6 +631,8 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz", "integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==", "dev": true, + "license": "MIT", + "peer": true, "engines": { "node": ">= 8" } @@ -605,6 +642,7 @@ "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", "dev": true, + "license": "ISC", "engines": { "node": "^12.20 || ^14.13.1 || >= 16" }, @@ -613,10 +651,12 @@ } }, "node_modules/vite": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz", - "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==", + "version": "4.5.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", + "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -668,12 +708,13 @@ } }, "node_modules/vitefu": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.4.tgz", - "integrity": "sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", "dev": true, + "license": "MIT", "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" }, "peerDependenciesMeta": { "vite": { diff --git a/v3/examples/screen/main.go b/v3/examples/screen/main.go index 75d0c8bd2..95db96705 100644 --- a/v3/examples/screen/main.go +++ b/v3/examples/screen/main.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "runtime" + "strings" "github.com/wailsapp/wails/v3/pkg/application" ) @@ -44,12 +45,22 @@ func main() { _, filename, _, _ := runtime.Caller(0) dir := filepath.Dir(filename) - url := r.URL.Path - path := dir + "/assets" + url + assetsDir := filepath.Join(dir, "assets") - if _, err := os.Stat(path); err == nil { + // Clean and validate the path to prevent directory traversal + cleanPath := filepath.Clean(r.URL.Path) + fullPath := filepath.Join(assetsDir, cleanPath) + + // Ensure the resolved path is still within the assets directory + if !strings.HasPrefix(fullPath, assetsDir+string(filepath.Separator)) && fullPath != assetsDir { + // Path traversal attempt detected, fall back to default handler + next.ServeHTTP(w, r) + return + } + + if _, err := os.Stat(fullPath); err == nil { // Serve file from disk to make testing easy - http.ServeFile(w, r, path) + http.ServeFile(w, r, fullPath) } else { // Passthrough to the default asset handler if file not found on disk next.ServeHTTP(w, r) diff --git a/v3/internal/setupwizard/wizard.go b/v3/internal/setupwizard/wizard.go index 7073f1fe1..2679f41f2 100644 --- a/v3/internal/setupwizard/wizard.go +++ b/v3/internal/setupwizard/wizard.go @@ -544,6 +544,15 @@ type InstallResponse struct { Error string `json:"error,omitempty"` } +// handleInstallDependency executes dependency installation commands. +// +// Security note: This endpoint executes commands that originate from the backend's +// package manager detection (see packagemanager.InstallCommand). The commands are +// generated server-side based on the detected OS package manager, not from arbitrary +// user input. This is a local development tool where the explicit purpose is to help +// users install dependencies on their own machine. The frontend currently only uses +// this data to copy commands to clipboard - this endpoint exists for potential future +// use or automation scenarios. func (w *Wizard) handleInstallDependency(rw http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(rw, "Method not allowed", http.StatusMethodNotAllowed) @@ -569,7 +578,7 @@ func (w *Wizard) handleInstallDependency(rw http.ResponseWriter, r *http.Request return } - cmd := exec.Command(parts[0], parts[1:]...) + cmd := exec.Command(parts[0], parts[1:]...) // #nosec G204 -- commands originate from backend package manager detection, not user input output, err := cmd.CombinedOutput() if err != nil {