Appearance
Rapport d'audit securite — Heriade (Addin + Backend)
Date : 2026-03-11 Auditeur : Claude Code (security-audit skill) Contexte : Production Scope : Audit complet (Addin Vue.js + Backend NestJS)
Resume executif
Le projet presente des fondations solides (JWT Supabase, Prisma parametrise, validation SQL des identifiants, multi-tenant scoping), mais souffre de lacunes critiques pour un deploiement production : CORS ouvert sans restriction, endpoints sensibles sans authentification (upload, enterprises, roles), cle de chiffrement avec fallback hardcode, et absence de rate limiting. 8 findings critiques necessitent une correction immediate.
Resultats
CRITIQUE — Corriger immediatement
| # | Vulnerabilite | OWASP | CWE | Fichier:ligne | Impact | Fix recommande |
|---|---|---|---|---|---|---|
| 1 | CORS sans restriction — app.enableCors() sans aucune configuration autorise toutes les origines | A05 | CWE-942 | back/src/main.ts:32 | Tout site peut envoyer des requetes API avec les credentials de l'utilisateur | Configurer origin: [process.env.FRONT_URL, process.env.ADDIN_URL], credentials: true, methods et allowedHeaders restreints |
| 2 | Upload sans authentification — 4 endpoints d'upload/listing de fichiers n'ont aucun @UseGuards(AuthGuard) | A01 | CWE-434 | back/src/upload/upload.controller.ts:10-36 | Upload de fichiers arbitraires par n'importe qui, listing des fichiers publics, DoS via fichiers volumineux | Ajouter @UseGuards(AuthGuard) sur tous les endpoints + validation de type MIME + limite de taille |
| 3 | Endpoints entreprises publics — GET /enterprises, /enterprises/:id, /enterprises/:id/users sans AuthGuard | A01 | CWE-200 | back/src/enterprise/enterprise.controller.ts:10-23 | Enumeration de toutes les entreprises et utilisateurs du systeme | Ajouter @UseGuards(AuthGuard) et filtrer par enterprise de l'utilisateur |
| 4 | Endpoint roles public — GET /roles sans AuthGuard | A01 | CWE-200 | back/src/role/role.controller.ts:9-12 | Enumeration des roles du systeme (reconnaissance) | Ajouter @UseGuards(AuthGuard) |
| 5 | Cle de chiffrement hardcodee — Fallback 'default_secret_key' si ENCRYPTION_KEY absent | A02 | CWE-321 | back/utils/external-db/encryptHelper.ts:4 | Tous les mots de passe BDD externes dechiffrables avec une cle connue | Rendre ENCRYPTION_KEY obligatoire, throw si absent ou < 32 chars |
| 6 | Headers de securite absents — Pas de Helmet : ni CSP, ni HSTS, ni X-Frame-Options, ni X-Content-Type-Options | A05 | CWE-693 | back/src/main.ts | Clickjacking, MIME sniffing, pas de HSTS, pas de CSP | npm i helmet puis app.use(helmet()) |
| 7 | Swagger expose en production — SwaggerModule.setup('api', app, document) sans condition d'environnement | A05 | CWE-215 | back/src/main.ts:57-58 | API surface completement visible (endpoints, parametres, schemas) | Conditionner a process.env.NODE_ENV !== 'production' |
| 8 | SSRF via connexion manuelle — manual-connect/* accepte n'importe quel host:port fourni par l'utilisateur | A10 | CWE-918 | back/src/data-pivot/data-pivot.service.ts:176-204 | Scan reseau interne, acces metadata AWS (169.254.169.254), pivot vers BDD internes | Bloquer IPs privees/localhost/link-local, whitelist de ports, ou supprimer la connexion manuelle |
HAUTE — Corriger avant mise en production
| # | Vulnerabilite | OWASP | CWE | Fichier:ligne | Impact | Fix recommande |
|---|---|---|---|---|---|---|
| 9 | IDOR sur PUT responses — saveRecordings et updateResponse n'injectent pas @CurrentUser(), aucune verification de propriete | A01 | CWE-639 | back/src/response/response.controller.ts:66-75 | Un utilisateur authentifie peut modifier n'importe quelle reponse par UUID | Ajouter @CurrentUser() user et verifier l'acces dans le service |
| 10 | Pas de rate limiting — Aucun @nestjs/throttler ou equivalent dans le codebase | A07 | CWE-307 | Global | Brute force sur login, enumeration, DoS sur les endpoints | Installer @nestjs/throttler, configurer globalement + limits specifiques sur auth |
| 11 | Body parser 256 MB — Limite de requete excessive | A04 | CWE-770 | back/src/main.ts:46-47 | DoS par envoi de payloads volumineux, exhaustion memoire | Reduire a 10-50 MB pour JSON, utiliser multer pour les uploads avec limites separees |
| 12 | JWT stocke en localStorage — Tokens access + refresh en localStorage, vulnerable au XSS | A07 | CWE-522 | addin/src/shared/authService.ts:23-24,80-81 | Si XSS present, vol de tokens et compromission de compte | Attenuer via CSP strict ; pour l'addin Office le risque est reduit par le sandbox, mais reste une mauvaise pratique |
| 13 | Echecs d'auth non logges — Aucun log des tentatives echouees avec contexte (IP, user_id) | A09 | CWE-778 | back/src/common/guards/authGuard.ts:155-156,218-237 | Impossible de detecter les attaques brute force ou les tentatives d'intrusion | Ajouter this.logger.warn(...) sur chaque point d'echec avec IP et contexte |
MOYENNE — A planifier
| # | Vulnerabilite | OWASP | CWE | Fichier:ligne | Impact | Fix recommande |
|---|---|---|---|---|---|---|
| 14 | LIMIT interpole en string — SELECT TOP ${limit} / LIMIT ${limit} sans parametrisation | A03 | CWE-89 | back/src/data-pivot/data-pivot.service.ts:310,312 | Risque faible (borne par Math.min/max), mais viole le principe de parametrisation | Utiliser des parametres prepares pour la clause LIMIT |
| 15 | Pas de validation DTO — limit?: number dans le body sans class-validator | A03 | CWE-20 | back/src/data-pivot/data-pivot.controller.ts:41,67 | Type coercion JS, NaN, Infinity possibles avant le clamping service | Creer un DTO avec @IsOptional() @IsNumber() @Min(1) @Max(100000) |
| 16 | MSSQL trustServerCertificate: true — Desactive la verification TLS pour SQL Server | A02 | CWE-295 | back/utils/external-db/dialectHelper.ts:126 | MITM possible sur connexions SQL Server | Configurer encrypt: true, trustServerCertificate: false en production |
| 17 | Redis localhost fallback — process.env.REDIS_HOST || 'localhost' sans validation | A05 | CWE-215 | back/src/app.module.ts | Cache non fonctionnel en multi-serveur si env var manquante | Throw en production si REDIS_HOST absent |
BASSE / Informationnel
| # | Observation | OWASP | Fichier:ligne | Recommandation |
|---|---|---|---|---|
| 18 | Regex identifiants SQL accepte espaces et points — ^[a-zA-Z_][a-zA-Z0-9_. ]*$ | A03 | back/utils/external-db/pivotQuery.ts:8 | Mitige par le quoting correct ; restreindre si les noms avec espaces ne sont pas necessaires |
| 19 | Credentials de test dans docker-compose — Mots de passe en clair dans le fichier compose de test | A02 | addin/docker-test-dbs/docker-compose.yml | Utiliser un .env.docker avec env_file: |
| 20 | Source maps desactivees en prod — devtool: isDev ? "source-map" : false | A05 | addin/webpack.config.js:101 | Deja correctement configure |
Dependances et CVE
Addin (npm audit) : 0 vulnerabilites trouvees.
Backend (yarn audit) : 160 vulnerabilites trouvees :
- 10 Critical
- 73 High
- 36 Moderate
- 41 Low
Principale CVE identifiee : file-type (boucle infinie sur input ASF malformed, affecte @nestjs/common et @swc/cli). Patch disponible : >=21.3.1.
Action recommandee : Executer yarn audit fix et mettre a jour les packages critiques. Les CVE critiques/high doivent etre evaluees individuellement.
Git history : Aucun secret committe dans l'historique (git log --all --source -- '*.env' '*.key' '*.pem' '*.secret' — resultat vide).
Points positifs
- SQL parametrise (Prisma.sql) : Toutes les requetes Prisma utilisent des template tags parametrises (A03)
- Validation SQL des identifiants :
quoteIdentifier()avec regex + echappement par dialect (A03) - Whitelist des agregations : Seuls SUM/AVG/COUNT/MIN/MAX sont autorises (A03)
- Multi-tenant scoping :
resolveConnection()filtre parenterprise_iddu JWT (A01) - JWT verification robuste : Signature HMAC-SHA256 + comparaison timing-safe + verification expiration (A07)
- Chiffrement AES-256-CTR : Mots de passe BDD externes chiffres au repos (A02)
- Connexions avec timeout :
connectionTimeoutMillis: 10_000sur toutes les BDD (A04) - ValidationPipe + whitelist :
whitelist: true, transform: truefiltre les proprietes inattendues (A03) - Source maps off en prod : Pas d'exposition du code source (A05)
- Pas de v-html : Aucune directive
v-htmldans les composants Vue (A03) - Pas d'eval/exec : Aucun usage de
eval(),exec(),Function()(A03) - .env dans .gitignore : Fichiers d'environnement non committes (A02)
- Logout nettoie localStorage :
signOut()supprime tokens + appelle Supabase (A07) - Sanitisation des noms de feuilles Excel : Caracteres invalides filtres, longueur tronquee a 31 (A03)
Score global
| Categorie OWASP | Score | Justification |
|---|---|---|
| A01 - Broken Access Control | 3/10 | Endpoints sans auth (upload, enterprises, roles), IDOR sur responses |
| A02 - Cryptographic Failures | 6/10 | AES-256 en place mais cle fallback hardcodee, MSSQL sans TLS |
| A03 - Injection | 8/10 | Requetes parametrisees, validation identifiants, pas de XSS |
| A04 - Insecure Design | 5/10 | Pas de rate limiting, body 256MB, SSRF possible |
| A05 - Security Misconfiguration | 2/10 | CORS *, pas de Helmet, Swagger en prod |
| A06 - Vulnerable Components | 4/10 | 160 vulns dans le backend (yarn audit) |
| A07 - Auth Failures | 6/10 | JWT correct mais pas de rate limiting, tokens en localStorage |
| A08 - Software & Data Integrity | 7/10 | Pas de SRI necessaire (pas de CDN), webhooks N/A |
| A09 - Logging & Monitoring | 3/10 | Logs basiques, echecs auth non traces, pas d'alerting |
| A10 - SSRF | 3/10 | Connexion manuelle sans filtrage d'IP/port |
Score global : 4.5/10
Le projet a de bonnes bases techniques (SQL parametrise, JWT, multi-tenant), mais les lacunes en configuration de securite (CORS, headers, endpoints non proteges) et l'absence de defense en profondeur (rate limiting, logging securite, filtrage SSRF) le rendent non deplorable en production en l'etat.
Prochaines etapes
| Priorite | Action | Effort estime | Fichier(s) |
|---|---|---|---|
| P0 | Configurer CORS avec whitelist d'origines | ~30 min | main.ts |
| P0 | Ajouter @UseGuards(AuthGuard) sur upload, enterprise, role controllers | ~1h | 3 controllers |
| P0 | Installer + configurer Helmet | ~15 min | main.ts |
| P0 | Rendre ENCRYPTION_KEY obligatoire (throw si absent) | ~15 min | encryptHelper.ts |
| P0 | Desactiver Swagger en production | ~5 min | main.ts |
| P1 | Ajouter @CurrentUser() sur PUT responses (saveRecordings, update) + verif acces | ~1h | response.controller.ts, response.service.ts |
| P1 | Installer @nestjs/throttler + configurer rate limiting | ~1h | app.module.ts, controllers |
| P1 | Bloquer IPs privees/localhost dans connexions manuelles | ~2h | data-pivot.service.ts |
| P1 | Ajouter logging des echecs d'auth (IP, user_id, raison) | ~1h | authGuard.ts |
| P2 | Reduire bodyParser.limit a 10-50 MB | ~5 min | main.ts |
| P2 | Creer DTOs avec class-validator pour data-pivot | ~1h | data-pivot.controller.ts |
| P2 | yarn audit fix + mise a jour packages critiques | ~2h | package.json |
| P2 | Parametriser LIMIT dans les requetes SQL | ~30 min | data-pivot.service.ts |
Avertissement
Ce rapport a ete genere par un outil automatise (Claude Code) et constitue une aide a l'audit, pas un audit professionnel certifie. Les findings doivent etre relus et valides par un developpeur ou un expert securite avant toute action corrective. Certains resultats peuvent etre des faux positifs ou ne pas s'appliquer a votre contexte specifique. Ne transmettez pas ce rapport tel quel a une equipe technique sans l'avoir prealablement verifie.
