Where a weakness in one repository exposes the others — confirmed shared secrets, credential reuse, systemic root causes, and multi-repo attack chains across the 13-repo estate.
The per-repo reports rate each codebase in isolation. This page connects them. A-List's repositories are not independent: they share databases, secrets, integrations and a single backend. That means the effective blast radius of several findings is far larger than any one report shows — and the weakest repo (often an abandoned one) becomes the entry point to the most valuable system. Secret values below are redacted; a label like #7b937a43 is a short hash used only to prove two repositories contain the identical value.
One leaked Bitbucket app password (in the iOS app) unlocks every repository; from there an attacker harvests the platform backend's committed Firebase, OAuth and Stripe secrets to impersonate A-List's services. Independently, an abandoned repo (a-list-demo) ships live credentials to the same production database that the active alist-partner API uses — so dead code is a live data-breach path. Credential reuse (DB, Slack, monday.com) and a shared dev API URL across 7 repos mean issues do not stay contained.
Confirmed by literal matching across the working trees (and recoverable from git history). Hashes prove equality without revealing the secret.
| Cluster | Repos sharing it | Evidence | Blast radius | Sev |
|---|---|---|---|---|
| Bitbucket app password | grants access to all 13 | committed a-list-ios/README:10, AppDelegate.swift:18 |
Clone every repo in the workspace → harvest every secret in this table. The master key. | P0 |
| Production database credentials | a-list-demo · alist-v2 · alist-partner | same DB name + user #7b937a43/#dc76e9f0 in all three; demo & v2 also share the DB password #bfb71705 |
Live creds committed in the abandoned demo/v2 repos point at the same database the active partner API uses → cross-app PII read/write from dead code. | P0 |
| Slack incoming webhooks | alist-portal · alist-partner · a-list-demo | reused hooks #b12111a0 (portal+partner), #56a6484d & #fa7069fc (portal+demo) |
One leaked webhook lets an attacker post/spoof messages into A-List's Slack workspace from any of three repos; phishing & ops-channel abuse. | P1 |
| monday.com API token | alist-portal · a-list-demo (+ creators-website ships its own) | same JWT #edafd98b in portal + demo; creators-website inlines a monday JWT into its public JS bundle |
Read/write the monday.com workspace (CRM/leads) from the backend, the legacy fork, and — via the browser bundle — anyone who views the creators site. | P1 |
| Firebase API key | a-list-demo · a-list-ios · alist-android · alist-portal · alist-v2 | AIza… key present in 5 repos | Same Firebase project referenced across mobile, backend and legacy. Combined with the committed Firebase Admin service-account key in portal, enables push/abuse against the whole user base. | P1 |
| Dev API base URL in prod builds | a-list-ios · alist-android · alist-vendors · alist-website · alist-portal · alist-cms · alist-v2 (7) | dev-*.alist.ae hardcoded (android: 7 refs incl. production EAS profile) | Production mobile/web clients trust a lower-trust dev backend → one dev-environment compromise or MitM affects production users across the estate. | P1 |
Patterns the per-repo scanners reported again and again. Each has a single upstream control that would fix it across the org.
| Pattern | Repos | Why it recurs | One control that fixes it estate-wide |
|---|---|---|---|
| Secrets committed to git (& history) | all backends + mobile | No secret scanning; reactive .gitignore added after files were committed, so they remain in history. | Mandatory pre-commit gitleaks + CI secret-scan gate; secrets manager (Vault/Doppler/SSM); history purge. |
| No CI/CD, no tests, no SCA | ~all 13 | Manual FTP/Xcode/EAS deploys from laptops; nothing surfaces regressions or CVEs. | A baseline pipeline per repo: lint + test + SAST + SCA + secret-scan, blocking merge. |
| No authorization framework | Laravel services | Auth is done with inline registration_type string checks and route placement instead of Policies/Gates/middleware; routes outside the inner group silently become public. | Centralised Policy/Gate layer + default-deny route middleware; authorization tests. |
| Shared production DB as one trust boundary | demo · v2 · partner (+ portal) | Apps were forked/branched and kept pointing at the same database and credentials. | Separate databases + least-privilege DB users per service; rotate shared creds. |
| EOL runtimes & outdated components | 10 / 13 | PHP 7.x / Laravel 6–9, CRA, node-sass, old Strapi left in place; no dependency monitoring. | Upgrade to supported majors; Dependabot/Renovate + SCA in CI. |
| Error-message disclosure & debug endpoints | portal · partner · demo | Catch-all handlers return $e->getMessage(); phpinfo/error_log/test routes shipped. | Global exception handler returning generic errors; APP_DEBUG=false in prod; remove debug routes. |
a-list-ios (README:10 / AppDelegate.swift:18).alist-portal read the committed APP_KEY, Passport RSA private key, Firebase Admin SA key, Google OAuth secrets and Stripe keys.a-list-demo (frozen 2020, but still in Bitbucket) commits live DB_* credentials.#7b937a43/#dc76e9f0) — and demo↔v2 the same password (#bfb71705) — as the active alist-partner API.alist-portal exposes an unauthenticated IDOR that discloses any user's verification PIN.a-list-ios sets NSAllowsArbitraryLoads=true with no certificate pinning; alist-android accepts cleartext and ships the dev API URL in its production build.alist-portal's /v1/* API.alist-vendors renders API-supplied HTML through 7 dangerouslySetInnerHTML sinks without sanitization.localStorage, "encrypted" with a hardcoded passphrase present in the source — trivially decryptable; exfiltrate it.dev-*.alist.ae URL; a dev-environment compromise reaches production users.alist-portal's Firebase Admin key, both Google OAuth secret+refresh pairs, APP_KEY, Stripe and Passport keys.