Backend Docs

Click a node for docs

Plan d’action — Offboarding

Objectif : 0 regain d’accès. Couper les comptes, rotater les secrets qu’ils ont déjà clonés en local, vérifier qu’il ne reste rien d’exploitable. Runbook détaillé (phases + tests + scripts) : docs/OFFBOARDING_CHECKLIST.md.

Principe directeur. Un dev qui a cloné les repos a déjà les secrets en local. Le retirer de GitHub ne désactive PAS les secrets qu’il possède. Il faut donc révoquer les comptes (Phase 1) et rotater les secrets (Phase 2) en parallèle, pas séquentiellement.

Surface concernée (rappel rapide)

  • (pejisdev) — admin HyperSwap-Labs/charting_library ; push sur interface, terminal-perps, api-front-hyperswap, grid-front-hyperswap ; commits dans indexer-terminal.
  • (ExceptHL) — push sur interface, terminal-perps, api-front-hyperswap, grid-front-hyperswap.
  • Repos prod & secrets en jeu : terminal-perps/server/.env, hs-interface-lts, indexer-terminal, shadow-syndicate/*.

Type 1 vs Type 2 — la distinction qui structure tout

  • Type 1 — comptes personnels (login propre) : MongoDB Atlas, Railway, Cloudflare, AWS IAM, Privy, Banxa, Sentry, GitHub orgs, SSH Hostkey, Tawk.to, Yandex, GA4. → Phase 1 suffit.
  • Type 2 — credentials partagés (valeurs en .env / hardcodés) : MONGODB_URL, INDEXER_DATABASE_URL, JWT_SECRET, PRIVY_APP_SECRET, BANXA_API_SECRET, AWS_ACCESS_KEY_*, ENCRYPTION_KEY, clé Alchemy leakée, Telegram bot tokens, npm publish tokens. → Seule la Phase 2 (rotation) tue l’accès.
3 cas où l’ordre est obligatoirement séquentiel :
  1. charting_library : PJ est ADMIN. Transférer admin à HyperSwapX AVANT de le retirer (sinon repo orphelin).
  2. shadow-syndicate : admin = kindex. Il peut ré-inviter en 30s. Briefer kindex ou faire passer HSX admin avant Phase 1.
  3. indexer-terminal defaults committés (GF_SECURITY_ADMIN_PASSWORD=admin, Postgres indexer_password). Vérifier en Phase 0 que la prod override, sinon les rotations Phase 2 ne servent à rien (bypass via les defaults).

Phase 0 — Préparation (T-2h → T-30min, sans qu'ils le sachent)

  • Canal de coordination privé (CTO + DevOps + 1 personne dédiée révocation) ; aligner timing avec RH.
  • Pré-générer toutes les nouvelles valeurs de secrets dans 1Password / Vault partagé.
  • Préparer les scripts de redéploiement Railway / Cloudflare Pages (avec nouveaux env vars) — ne pas déclencher.
  • Snapshot Postgres + MongoDB (anti-sabotage entre T+0 et T+30min).
  • Vérifier qu’on a les credentials owner de chaque dashboard (Atlas, Railway, AWS, Cloudflare, Privy, Banxa, LiveKit, Sentry).
  • Vérifier que la prod override les defaults indexer-terminal : ssh root@146.0.73.21 'grep -i security_admin_password /etc/grafana/grafana.ini'.

Phase 1 — Kill sessions (T+0 → T+5min, en parallèle de Phase 2)

  • GitHub : retirer des orgs (HSX-Labs, HyperswapFoundation, shadow-syndicate). Pour les outside-collab, boucle gh api -X DELETE repos/{org}/{repo}/collaborators/{user}.
  • SSH Hostkey VPS (146.0.73.21) : retirer leur clé publique de /root/.ssh/authorized_keys ; si root password partagé, le changer maintenant.
  • Cloudflare, AWS Console (IAM disable), MongoDB Atlas (Project Access), Railway (Members), DigitalOcean, Vast.AI, Hostkey provider, Privy (4 apps), Banxa, LiveKit, Sentry, Tawk.to, Yandex Metrika, GA4, Mobula / NewsData / Financiya / Transak.

Checkpoint : ils ne peuvent plus se connecter avec leur propre compte. Mais ils ont encore les secrets locaux → continuer Phase 2.

Phase 2 — Rotation des secrets (T+5 → T+30min)

2a. Backend — terminal-perps/server/.env

  • MONGODB_URL : changer le password user evan-hl dans Atlas → update Railway env → redeploy server.
  • INDEXER_DATABASE_URL : ALTER USER indexer WITH PASSWORD 'newpw'; sur Hostkey ; LIQUIDSCAN_DATABASE_URL idem sur 54.37.85.136.
  • JWT_SECRET : nouveau 256-bit hex, redeploy. ⚠ invalide tous les JWT users actifs.
  • PRIVY_APP_SECRET + PRIVY_AUTH_PRIVATE_KEY : rotate dans Privy + update Railway env.
  • BANXA_API_KEY/_SECRET, LIVEKIT_API_KEY/_SECRET, TRANSAK_API_KEY/_SECRET (⚠ TRANSAK_* shippé en frontend → redeploy front simultané), AWS_ACCESS_KEY_ID/_SECRET (IAM new key + disable old).
  • MOBULA_API_KEY, FINANCIYA_API_KEY, NEWSDATA_API_KEY : rotate.
  • REFERRAL_CLAIM_PRIVATE_KEY : ⚠ clé de signature on-chain → régénérer puis rotater l’authorized signer dans le contrat (tx on-chain).
  • ANONYMIZE_SALT : rotater (casse les hashes anonymisés existants — accepter la perte d’historique).

2b. Frontend — hs-interface-lts / interface

  • ENCRYPTION_KEY (XOR hardcodé) : changer la valeur, redeploy front, regénérer tous les x-client-token côté CF Workers.
  • SENTRY_AUTH_TOKEN : Sentry → Auth Tokens → revoke + create + update GitHub Actions secret.

2c. shadow-syndicate (RRC + Grid)

  • 🔥 Alchemy key leakée qZxKitp1_VDz9MuohnrZQ4KUTHtaQ-6g (api-front-hyperswap/.env.development) → DELETE dans Alchemy + nouvelle clé en GitHub Actions secret. Purger l’historique git.
  • Telegram bot tokens (@roachracingclub, @mineasudasd_bot) → @BotFather /revoke.
  • api-dev2.roachracingclub.com admin password (si l’employé l’avait).

2d. Supply chain

  • NPM publish tokens @hyperswap-labs/* → revoke tous + 1 token org-shared en GitHub Actions secret.
  • Cloudflare API token (utilisé par deploy.yml) → revoke + create + update GitHub Actions secret.
  • REFERRAL_API_KEY (Grafana) → noter, ajouter à .env.example, redeploy Grafana.

2e. Defaults committés à override (CRITIQUE)

  • Si Phase 0 a montré que la prod utilise les defaults d’indexer-terminal/docker-compose.yml : override GF_SECURITY_ADMIN_PASSWORD + POSTGRES_PASSWORD, restart Docker.

Checkpoint : tous les secrets locaux de sont des chaînes inertes. Les publier sur Twitter ne donne plus accès à rien.

Phase 3 — Cleanup (T+30min → T+24h)

  • Boucle gh api -X DELETE sur tous les repos outside-collab (HSX-Labs : interface, terminal-perps, charting_library, indexer-terminal ; shadow-syndicate : api-front-hyperswap, grid-front-hyperswap).
  • Wallets on-chain : retirer de MODERATOR_ADDRESSES et WHITELISTED_WALLETS (server/.env) → redeploy.
  • Slack / Discord / Telegram team channels, Notion / docs internes, Apple Dev / Google Play, 1Password / Bitwarden / Vault partagé.

Phase 4 — Audit & monitoring (T+24h → T+7j)

  • GitHub Audit log (chaque org, 7 derniers jours), AWS CloudTrail, Cloudflare audit log, MongoDB Atlas Activity Feed, Privy Activity log.
  • Hostkey VPS : last -F | head -50; lastlog | head + scan des fichiers récemment modifiés.
  • Failed-login alerts pendant 7 jours (détection d’une tentative de retour).

Phase 4.5 — Test de non-régression (à T+30min, AVANT de clore)

Prendre le .env qu’ils possédaient et tester chaque ligne. Si un seul test passe, retour Phase 2 sur la ligne précisément.

  • MongoDB : mongosh "$OLD_MONGO" --eval "db.adminCommand('ping')" doit échouer (Authentication failed).
  • Postgres : psql "$OLD_PG" -c "SELECT 1" doit échouer.
  • AWS : aws sts get-caller-identity avec les anciennes keys doit retourner InvalidClientTokenId.
  • Privy / Banxa : appel API avec les anciens secrets doit retourner 401/403.
  • JWT : forger un JWT avec l’ancien JWT_SECRET et hit l’API → 401.
  • Alchemy (clé leakée) : eth_blockNumber avec l’ancienne clé → 401/403.
  • SSH Hostkey : tentative connexion avec leur ancienne clé → Permission denied.

Phase 5 — Vérifications finales

  • Comptes “admin partagés” (ex: admin@hyperswap.exchange) dont plusieurs personnes connaissaient le password.
  • Outils internes auto-hébergés (Grafana, métriques, k8s admin si applicable).
  • Cron / scripts sur Hostkey utilisant un de leurs tokens : crontab -l; ls /etc/cron.*.
  • Cloudflare Workers publiés sous leur Account ID perso (workers déployés perso peuvent encore tourner).
  • Owner du Worker proxy-nft-mint.hyperswapx.workers.dev.

Spécifique PJ (pejisdev)

  • ADMIN charting_library → transfert admin à HyperSwapX AVANT remove.
  • Commits dans indexer-terminal → connaît la structure DB et les defaults. Override defaults obligatoire avant Phase 2.
  • Push très récent sur terminal-perps (jusqu’au 2026-04-22) → audit ses derniers commits pour repérer toute backdoor.

Spécifique Evan (ExceptHL)

  • Push (pas admin) sur 4 repos. Pas d’access cross-org étendu détecté → risk medium.
  • Email obfusqué (@users.noreply.github.com) → traçage hors-GitHub impossible.
  • Activité publique récente sur d’autres orgs (jovanpanetie/stake-engine-md-doc) → indicateur de mobilité, pas un risque direct.

Règle de tri si tu dois choisir quoi rotater en premier

  1. Ce qui donne admin (GitHub orgs, Cloudflare API, AWS IAM, Privy app secrets, registrar).
  2. Ce qui donne prod (SSH Hostkey, MongoDB/Postgres admin, Railway).
  3. Ce qui permet signer/forger (JWT, webhook secrets Banxa/LiveKit, REFERRAL_CLAIM_PRIVATE_KEY).
  4. Le reste (Sentry, GA4, Tawk.to, Yandex, NewsData, Mobula, Financiya).