security: round 4 — frontend hardening (deps, XSS, cookie security)

Vulnerable dependencies upgraded:
- Backend: league/commonmark >=2.8.2 (HTML injection bypass),
  phpunit/phpunit >=11.5.50, laravel/tinker (psysh LPE)
- Frontend: axios 1.13→1.15 (SSRF + metadata exfiltration),
  @casl/ability updated (prototype pollution)
- Removed swiper from all 3 apps (prototype pollution CVE,
  only used in Vuexy demo pages)

XSS vectors removed:
- Deleted Vuexy demo pages with v-html rendering API data:
  help-center/article, academy/course-details
- Deleted all front-pages (landing, pricing, checkout, payment) —
  Vuexy marketing template, not Crewli business logic
- Deleted swiper demo components and views
- Fixed admin main.ts: replaced innerHTML with template literal
  with safe DOM construction using textContent

Cookie security:
- Added SameSite=Strict and Secure flags to admin cookie defaults

Cleanup:
- Removed swiper SCSS from all 3 apps
- Removed swiper custom element config from all 3 vite configs
- Portal localStorage cleanup verified: reset() clears all keys,
  called on both explicit logout and 401 interceptor

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-14 07:15:00 +02:00
parent 52f6380ac0
commit b8286d6a84
51 changed files with 694 additions and 7224 deletions

View File

@@ -30,7 +30,7 @@
"@vueuse/core": "10.11.1",
"@vueuse/math": "10.11.1",
"apexcharts": "3.54.1",
"axios": "^1.13.2",
"axios": "^1.15.0",
"chart.js": "4.5.1",
"cookie-es": "1.2.2",
"destr": "2.0.5",
@@ -42,7 +42,6 @@
"prismjs": "1.30.0",
"roboto-fontface": "0.10.0",
"shepherd.js": "13.0.3",
"swiper": "11.2.10",
"ufo": "1.6.1",
"unplugin-vue-define-options": "1.5.5",
"vee-validate": "^4.15.1",

154
apps/app/pnpm-lock.yaml generated
View File

@@ -61,8 +61,8 @@ importers:
specifier: 3.54.1
version: 3.54.1
axios:
specifier: ^1.13.2
version: 1.13.2
specifier: ^1.15.0
version: 1.15.0
chart.js:
specifier: 4.5.1
version: 4.5.1
@@ -96,9 +96,6 @@ importers:
shepherd.js:
specifier: 13.0.3
version: 13.0.3
swiper:
specifier: 11.2.10
version: 11.2.10
ufo:
specifier: 1.6.1
version: 1.6.1
@@ -1990,8 +1987,8 @@ packages:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
axios@1.13.2:
resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
axios@1.15.0:
resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@@ -2017,6 +2014,9 @@ packages:
brace-expansion@1.1.12:
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
brace-expansion@1.1.14:
resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==}
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
@@ -2454,6 +2454,9 @@ packages:
eslint: ^7.32.0 || ^8.2.0
eslint-plugin-import: ^2.25.2
eslint-import-resolver-node@0.3.10:
resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==}
eslint-import-resolver-node@0.3.9:
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
@@ -2806,8 +2809,8 @@ packages:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
form-data@4.0.4:
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
fs-minipass@2.1.0:
@@ -2870,6 +2873,9 @@ packages:
get-tsconfig@4.13.0:
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
get-tsconfig@4.13.7:
resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==}
gl-matrix@3.4.4:
resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==}
@@ -3418,6 +3424,9 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@3.1.5:
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
minimatch@9.0.3:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'}
@@ -3501,6 +3510,10 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
node-exports-info@1.6.0:
resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==}
engines: {node: '>= 0.4'}
node-fetch-native@1.6.7:
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
@@ -3841,8 +3854,9 @@ packages:
protocol-buffers-schema@3.6.0:
resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
proxy-from-env@2.1.0:
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
engines: {node: '>=10'}
psl@1.15.0:
resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
@@ -3948,6 +3962,16 @@ packages:
engines: {node: '>= 0.4'}
hasBin: true
resolve@1.22.12:
resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==}
engines: {node: '>= 0.4'}
hasBin: true
resolve@2.0.0-next.6:
resolution: {integrity: sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==}
engines: {node: '>= 0.4'}
hasBin: true
reusify@1.1.0:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -4021,6 +4045,11 @@ packages:
engines: {node: '>=10'}
hasBin: true
semver@7.7.4:
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
engines: {node: '>=10'}
hasBin: true
serialize-to-js@3.1.2:
resolution: {integrity: sha512-owllqNuDDEimQat7EPG0tH7JjO090xKNzUtYz6X+Sk2BXDnOCilDdNLwjWeFywG9xkJul1ULvtUQa9O4pUaY0w==}
engines: {node: '>=4.0.0'}
@@ -4302,10 +4331,6 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
swiper@11.2.10:
resolution: {integrity: sha512-RMeVUUjTQH+6N3ckimK93oxz6Sn5la4aDlgPzB+rBrG/smPdCTicXyhxa+woIpopz+jewEloiEE3lKo1h9w2YQ==}
engines: {node: '>= 4.7.0'}
synckit@0.11.11:
resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -5398,7 +5423,7 @@ snapshots:
'@iconify/types': 2.0.0
'@iconify/utils': 2.3.0
'@types/tar': 6.1.13
axios: 1.13.2
axios: 1.15.0
cheerio: 1.0.0
domhandler: 5.0.3
extract-zip: 2.0.1
@@ -6723,11 +6748,11 @@ snapshots:
dependencies:
possible-typed-array-names: 1.1.0
axios@1.13.2:
axios@1.15.0:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.4
proxy-from-env: 1.1.0
form-data: 4.0.5
proxy-from-env: 2.1.0
transitivePeerDependencies:
- debug
@@ -6748,6 +6773,11 @@ snapshots:
balanced-match: 1.0.2
concat-map: 0.0.1
brace-expansion@1.1.14:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
@@ -7245,6 +7275,14 @@ snapshots:
object.entries: 1.1.9
semver: 6.3.1
eslint-import-resolver-node@0.3.10:
dependencies:
debug: 3.2.7
is-core-module: 2.16.1
resolve: 2.0.0-next.6
transitivePeerDependencies:
- supports-color
eslint-import-resolver-node@0.3.9:
dependencies:
debug: 3.2.7
@@ -7274,13 +7312,24 @@ snapshots:
esquery: 1.6.0
jsonc-eslint-parser: 2.4.1
eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-node: 0.3.10
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.10
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
@@ -7336,13 +7385,13 @@ snapshots:
debug: 3.2.7
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
get-tsconfig: 4.13.0
eslint-import-resolver-node: 0.3.10
eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
get-tsconfig: 4.13.7
is-glob: 4.0.3
minimatch: 3.1.2
resolve: 1.22.11
semver: 7.7.3
minimatch: 3.1.5
resolve: 1.22.12
semver: 7.7.4
transitivePeerDependencies:
- '@typescript-eslint/parser'
- eslint-import-resolver-typescript
@@ -7354,13 +7403,13 @@ snapshots:
debug: 3.2.7
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
get-tsconfig: 4.13.0
eslint-import-resolver-node: 0.3.10
eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
get-tsconfig: 4.13.7
is-glob: 4.0.3
minimatch: 3.1.2
resolve: 1.22.11
semver: 7.7.3
minimatch: 3.1.5
resolve: 1.22.12
semver: 7.7.4
transitivePeerDependencies:
- '@typescript-eslint/parser'
- eslint-import-resolver-typescript
@@ -7763,7 +7812,7 @@ snapshots:
dependencies:
is-callable: 1.2.7
form-data@4.0.4:
form-data@4.0.5:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
@@ -7838,6 +7887,10 @@ snapshots:
dependencies:
resolve-pkg-maps: 1.0.0
get-tsconfig@4.13.7:
dependencies:
resolve-pkg-maps: 1.0.0
gl-matrix@3.4.4: {}
glob-parent@5.1.2:
@@ -8393,6 +8446,10 @@ snapshots:
dependencies:
brace-expansion: 1.1.12
minimatch@3.1.5:
dependencies:
brace-expansion: 1.1.14
minimatch@9.0.3:
dependencies:
brace-expansion: 2.0.2
@@ -8470,6 +8527,13 @@ snapshots:
natural-compare@1.4.0: {}
node-exports-info@1.6.0:
dependencies:
array.prototype.flatmap: 1.3.3
es-errors: 1.3.0
object.entries: 1.1.9
semver: 6.3.1
node-fetch-native@1.6.7: {}
node-releases@2.0.27: {}
@@ -8857,7 +8921,7 @@ snapshots:
protocol-buffers-schema@3.6.0: {}
proxy-from-env@1.1.0: {}
proxy-from-env@2.1.0: {}
psl@1.15.0:
dependencies:
@@ -8967,6 +9031,22 @@ snapshots:
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
resolve@1.22.12:
dependencies:
es-errors: 1.3.0
is-core-module: 2.16.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
resolve@2.0.0-next.6:
dependencies:
es-errors: 1.3.0
is-core-module: 2.16.1
node-exports-info: 1.6.0
object-keys: 1.1.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
reusify@1.1.0: {}
rfdc@1.4.1: {}
@@ -9056,6 +9136,8 @@ snapshots:
semver@7.7.3: {}
semver@7.7.4: {}
serialize-to-js@3.1.2: {}
set-function-length@1.2.2:
@@ -9411,8 +9493,6 @@ snapshots:
csso: 5.0.5
picocolors: 1.1.1
swiper@11.2.10: {}
synckit@0.11.11:
dependencies:
'@pkgr/core': 0.2.9

View File

@@ -1,5 +0,0 @@
swiper-container {
--swiper-navigation-color: rgb(var(--v-theme-primary));
--swiper-navigation-size: 1.75rem;
--swiper-pagination-color: rgb(var(--v-theme-primary));
}

View File

@@ -27,14 +27,7 @@ export default defineConfig({
.toLowerCase();
},
}),
vue({
template: {
compilerOptions: {
isCustomElement: (tag) =>
tag === "swiper-container" || tag === "swiper-slide",
},
},
}),
vue(),
VueDevTools(),
vueJsx(),