33800 Docs

← Retour

Audit PASS 3 — connectors-api : INTEGRATION & CONTRATS INTER-SERVICES

Date : 15/02/2026 Status : IMPLEMENTEE Auditeur : Claude Opus 4.6 (pass independante) Projet : /stock_8to/33800-stack/projects/connectors-api/ Scope : Contrats API, Supabase, SSH, WireGuard, Auth flow, Proxy /api/fetch


Resume executif

Severite Nombre
BUG CERTAIN 5
BUG PROBABLE 6
RISQUE THEORIQUE 5
TOTAL 16

Les problemes les plus critiques :

  1. JWT non verifie — la signature HMAC n'est jamais validee, seul le payload base64 est decode
  2. wireguard.ts utilise la mauvaise API Supabase.from().select().eq().single() n'existe pas dans le wrapper custom
  3. 10+ endpoints sans authentification — incluant des endpoints d'administration critiques
  4. Injections de commandes SSH — via cwd, remotePath, et sshPublicKey
  5. Contenu heredoc non echappeescapedContent calcule mais jamais utilise

Findings

F-01 : JWT signature non verifiee


F-02 : wireguard.ts utilise l'API Supabase JS au lieu du wrapper custom

// supabase.ts - API reelle export const supabase = { select(table, options), insert(table, data), update(table, data, match), delete(table, match), // PAS de .from() };

- **Impact** : Toutes les operations VPN WireGuard (generateKeys, configure, connect, disconnect, getStatus, listActive, etc.) sont cassees. Le VPN ne fonctionne pas du tout.
- **Fix suggere** : Reecrire wireguard.ts pour utiliser `supabase.select('user_connectors', { filter: ... })` au lieu du chainage `.from()`.

---

### F-03 : 10+ endpoints sans authentification
- **Severite** : BUG CERTAIN
- **Fichier** : `src/index.ts` (multiples lignes)
- **Description** : Les endpoints suivants n'appellent jamais `getAuthFromRequest()` et sont accessibles sans token :
  - `DELETE /api/connectors/:id` (ligne 1112) — supprime un connecteur
  - `POST /api/connectors/:id/token` (ligne 1767) — definit un token systeme
  - `POST /api/connectors/:id/provision-type` (ligne 897) — change le type de provision
  - `GET /api/connectors/:id/schema` (ligne 1183) — lit le schema
  - `GET /api/connectors/:id/openapi` (ligne 1219) — lit l'OpenAPI spec
  - `GET /api/connectors/:id/endpoints` (ligne 1240) — lit les endpoints
  - `GET /api/endpoints/:id` (ligne 2072) — lit un endpoint
  - `GET /api/endpoints/:id/versions` (ligne 2088) — lit les versions
  - `GET /api/audit/logs/:id` (ligne 2000) — lit n'importe quel audit log
  - `GET /api/connectors/:id/logs` (ligne 2042) — lit les logs d'un connecteur
- **Code concerne** :
```typescript
// Exemple: DELETE sans auth
.delete('/api/connectors/:id', async ({ params }) => {
  // PAS de getAuthFromRequest() ici
  const result = await registry.deleteConnector(params.id);
  return result;
})

F-04 : SSH upload heredoc — escapedContent calcule mais jamais utilise


F-05 : SSH injection via cwd parameter


F-06 : SSH injection via remotePath


F-07 : SSH setupAutoKey injection via publicKey


F-08 : /api/fetch accessible sans authentification applicative


F-09 : audit.log() appele avec les mauvais noms de proprietes

// Interface correcte: interface AuditLogInput { userId: string; connectorId?: string; resourceId?: string; action: string; // ... }

- **Impact** : Les logs d'audit ne contiennent pas le userId, connectorId, ni resourceId car les proprietes snake_case sont ignorees par l'interface. Les logs sont incomplets.
- **Fix suggere** : Utiliser les bons noms de proprietes (camelCase) et retirer le deuxieme argument.

---

### F-10 : Chiffrement avec sel statique "salt"
- **Severite** : BUG PROBABLE
- **Fichier** : `src/services/ssh.ts:109`, `src/services/wireguard.ts:78`, `src/services/vpn-profiles.ts:78`
- **Description** : Les trois fichiers utilisent `crypto.scryptSync(ENCRYPTION_KEY, 'salt', 32)` avec un sel fixe. Le sel statique reduit la resistance de scrypt aux attaques par dictionnaire — toutes les cles derivees avec la meme ENCRYPTION_KEY produisent le meme resultat.
- **Code concerne** :
```typescript
const key = crypto.scryptSync(ENCRYPTION_KEY, 'salt', 32);

F-11 : convertToOpenSSH placeholder non fonctionnel


F-12 : Versions incoherentes entre package.json, /health, et Swagger


F-13 : getUserFromRequest (sync) ne peut pas valider les API keys

// Async - supporte JWT + API keys async function getAuthFromRequest(headers): Promise<{ userId: string } | null> { // Peut faire await apiKeys.verify(...) }

- **Impact** : Certains endpoints rejettent les utilisateurs avec API key s'ils utilisent le middleware sync au lieu de la fonction async.
- **Fix suggere** : Convertir `requireAuth()` en middleware async, ou documenter quels endpoints supportent les API keys.

---

### F-14 : AI webhook secret optionnel
- **Severite** : RISQUE THEORIQUE
- **Fichier** : `src/index.ts:4936-5045`
- **Description** : Le webhook AI verifie le secret uniquement si `AI_WEBHOOK_SECRET` est defini dans les variables d'environnement. Si la variable n'est pas definie, n'importe quelle requete est acceptee.
- **Code concerne** :
```typescript
if (expectedSecret && secret !== expectedSecret) {
  // Si expectedSecret est vide/undefined, la condition est false -> requete acceptee
  return { success: false, error: 'Invalid secret' };
}

F-15 : NODE_TLS_REJECT_UNAUTHORIZED=0 en production


F-16 : /api/fetch/upload accessible sans authentification


Synthese par axe d'audit

1. Contrats API exposes

2. Integration Supabase

3. Integration SSH

4. Integration WireGuard

5. Auth flow complet

6. Proxy /api/fetch