Cross-Repo Correlation

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.

MethodHash-verified secret reuse + systemic pattern analysis Repos analysed13 EvidenceLiteral matches in the working tree (values redacted) Generated2026-05-30

Why this matters

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.

Headline

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.

Estate-level risk
Critical
5secret clusters5attack chains

1 · Shared-secret & credential-reuse clusters

Confirmed by literal matching across the working trees (and recoverable from git history). Hashes prove equality without revealing the secret.

ClusterRepos sharing itEvidenceBlast radiusSev
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

2 · Systemic root causes

Patterns the per-repo scanners reported again and again. Each has a single upstream control that would fix it across the org.

PatternReposWhy it recursOne control that fixes it estate-wide
Secrets committed to git (& history)all backends + mobileNo 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 13Manual 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 frameworkLaravel servicesAuth 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 boundarydemo · 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 components10 / 13PHP 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 endpointsportal · partner · demoCatch-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.

3 · Cross-repo attack chains

CHAIN-A

Bitbucket key → clone everything → forge platform admin tokens

Kill chain
1. Extract the committed Bitbucket app password from a-list-ios (README:10 / AppDelegate.swift:18).
2. Authenticate to Bitbucket → clone all 13 repos (the password is workspace-scoped).
3. From alist-portal read the committed APP_KEY, Passport RSA private key, Firebase Admin SA key, Google OAuth secrets and Stripe keys.
4. Forge Passport/JWT tokens and call backend services as any user/admin; push notifications via Firebase Admin.
Impact: full compromise of the platform and its integrations.
CHAIN-B

Abandoned repo → live production database

Kill chain
1. a-list-demo (frozen 2020, but still in Bitbucket) commits live DB_* credentials.
2. Those credentials share the same DB name/user (#7b937a43/#dc76e9f0) — and demo↔v2 the same password (#bfb71705) — as the active alist-partner API.
3. If the database is network-reachable (or via the legacy cPanel host), read/write the production dataset directly.
Impact: cross-app PII breach and data tampering, originating entirely from dead code nobody is watching.
CHAIN-C

Unauthenticated account takeover of the creator base

Kill chain
1. alist-portal exposes an unauthenticated IDOR that discloses any user's verification PIN.
2. The 4-digit OTP login has no lockout and the OTP is echoed back in the API response; a static backdoor OTP also exists.
3. Authenticate as any creator/admin without their device.
Impact: mass account takeover; no MFA stands in the way.
CHAIN-D

Mobile MitM via disabled transport security

Kill chain
1. a-list-ios sets NSAllowsArbitraryLoads=true with no certificate pinning; alist-android accepts cleartext and ships the dev API URL in its production build.
2. On hostile Wi-Fi, intercept the API session and steal the bearer token.
3. Replay the token against alist-portal's /v1/* API.
Impact: session theft and impersonation for any mobile user on an untrusted network.
CHAIN-E

Stored XSS → vendor-admin session theft

Kill chain
1. alist-vendors renders API-supplied HTML through 7 dangerouslySetInnerHTML sinks without sanitization.
2. A malicious campaign/review/offer payload executes JS in an admin's browser.
3. The auth token lives in localStorage, "encrypted" with a hardcoded passphrase present in the source — trivially decryptable; exfiltrate it.
Impact: vendor-admin account takeover and pivot into the partner API.

4 · Shared trust boundaries

5 · Org-level remediation program

Phase 0 — contain (today)
  • Revoke the Bitbucket app password first (Bitbucket → app passwords) — it unlocks everything else.
  • Rotate the shared DB credentials and begin separating the partner/creator/portal databases; kill demo/v2's access.
  • Rotate alist-portal's Firebase Admin key, both Google OAuth secret+refresh pairs, APP_KEY, Stripe and Passport keys.
  • Rotate the shared Slack webhooks and the monday.com token; remove the monday token from the creators-website bundle.
  • Confirm the legacy cPanel hosts (a-list-demo) are offline.
Phase 1 — week
  • Break the unauthenticated ATO chain (PIN-disclosure IDOR, OTP echo, backdoor OTP, add OTP rate-limiting/lockout).
  • Parameterise the confirmed SQL injections; add auth middleware to the ungated admin routes.
  • Move SPA tokens to HttpOnly cookies; sanitize the XSS sinks in alist-vendors.
Phase 2 — month
  • Introduce a real authorization layer (Policies/Gates) across the Laravel services.
  • Separate dev vs prod API configuration per build; lock down CORS and add security headers; fix SSRF on image fetches.
  • Upgrade EOL runtimes (PHP 7.x → 8.2+) and patch Strapi.
Phase 3 — quarter (structural)
  • CI/CD on every repo with gitleaks + SAST + SCA gates and pre-commit hooks; commit lockfiles.
  • Adopt a secrets manager; purge secrets from git history across the workspace; scheduled rotation.
  • Per-service least-privilege DB users; automated tests and error/crash monitoring.