diff --git a/ASVS_CHECKLIST_v0.12.6.md b/ASVS_CHECKLIST_v0.12.6.md new file mode 100644 index 000000000..722438308 --- /dev/null +++ b/ASVS_CHECKLIST_v0.12.6.md @@ -0,0 +1,232 @@ +# CHECKLIST ASVS v4.0 Level 2 — VEZA v0.12.6 + +> **Date** : 2026-03-11 +> **Référence** : PENTEST_REPORT_VEZA_v0.12.6.md +> **Légende** : ✅ PASS | ❌ FAIL | ⚠️ PARTIEL | N/A | 🔍 NON VÉRIFIABLE (nécessite env live) + +--- + +## V1 — Architecture, Design and Threat Modeling + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V1.1.1 | Architecture documentée | ✅ PASS | Architecture hexagonale documentée dans CLAUDE.md + AUDIT_TECHNIQUE | — | +| V1.1.2 | Threat model exists | ⚠️ PARTIEL | Menaces identifiées dans les audits mais pas de threat model formel (STRIDE/DREAD) | — | +| V1.1.3 | Security controls documented | ✅ PASS | Middleware chain, RBAC, auth flow documentés | — | +| V1.2.1 | Layered architecture | ✅ PASS | Handler → Service → Repository — séparation claire | — | +| V1.4.1 | Trusted service layer | ✅ PASS | Validation côté serveur, pas de confiance au client | — | +| V1.5.1 | Input validation centralized | ✅ PASS | Gin binding + validation tags + middleware validation | — | +| V1.6.1 | Cryptographic module | ✅ PASS | JWT service centralisé, bcrypt standardisé | — | +| V1.7.1 | Error handling consistent | ✅ PASS | apierror package, error_handler middleware | — | +| V1.8.1 | Data protection classified | ⚠️ PARTIEL | PII identifié mais pas de classification formelle des données | — | +| V1.11.1 | Business logic security | ⚠️ PARTIEL | Race condition marketplace identifiée | HIGH-001 | + +--- + +## V2 — Authentication + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V2.1.1 | Password min 12 chars | ✅ PASS | Backend valide ≥ 12 chars | — | +| V2.1.2 | Password max 128 chars | ✅ PASS | Validation struct tags | — | +| V2.1.4 | Password strength meter | ⚠️ PARTIEL | Frontend accepte 8 chars (mismatch) | LOW-001 | +| V2.1.7 | Breach password check | ⚠️ PARTIEL | Blocklist de 25 mots courants, pas d'intégration HaveIBeenPwned | — | +| V2.1.9 | No password composition rules | ✅ PASS | Complexité par longueur, pas de règles arbitraires | — | +| V2.2.1 | Anti-automation on auth | ✅ PASS | Rate limiting sur /auth/login, lockout configuré | — | +| V2.2.2 | Weak auth resistance | ✅ PASS | bcrypt cost 12, rate limiting | — | +| V2.2.3 | No user enumeration | ✅ PASS | Messages d'erreur génériques, timing constant | — | +| V2.3.1 | 2FA implementation | ✅ PASS | TOTP (RFC 6238), recovery codes | — | +| V2.4.1 | Bcrypt/Argon2 for passwords | ✅ PASS | bcrypt cost 12 | — | +| V2.5.1 | Password reset secure token | ✅ PASS | Token crypto/rand, single-use, TTL limité | — | +| V2.5.2 | Password reset no info leak | ✅ PASS | "If account exists, email sent" | — | +| V2.6.1 | Lookup secrets crypto random | ❌ FAIL | Recovery codes utilisent math/rand | MEDIUM-001 | +| V2.7.1 | OTP time-based (TOTP) | ✅ PASS | TOTP via pquerna/otp | — | +| V2.8.1 | Session binding | ✅ PASS | Session liée au user via token + DB | — | +| V2.9.1 | RSA keys ≥ 2048 bits | ✅ PASS | Code supporte RSA 2048+, ParsePKCS1/PKCS8 | — | +| V2.10.1 | API key entropy | ✅ PASS | Préfixe vza_ + token cryptographique | — | + +--- + +## V3 — Session Management + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V3.1.1 | Session token not in URL | ✅ PASS | Cookie httpOnly ou header Authorization | — | +| V3.2.1 | Session bound to user | ✅ PASS | Session DB avec user_id, vérifié à chaque requête | — | +| V3.2.2 | Session invalidated on logout | ✅ PASS | Token blacklist + session delete | — | +| V3.2.3 | Session timeout | ✅ PASS | Access token 5min, refresh 14j/30j | — | +| V3.3.1 | Session invalidated on password change | ✅ PASS | Token version incrémentée → tous les tokens invalidés | — | +| V3.3.2 | Logout invalidates server-side | ✅ PASS | Session supprimée en DB + token blacklist Redis | — | +| V3.4.1 | Cookie secure attributes | ✅ PASS | `COOKIE_SECURE=true, COOKIE_SAME_SITE=strict, COOKIE_HTTP_ONLY=true` en prod | — | +| V3.4.2 | Cookie httpOnly | ✅ PASS | Configuré via env var | — | +| V3.4.3 | Cookie secure flag | ✅ PASS | Configuré via env var | — | +| V3.4.4 | Cookie SameSite | ✅ PASS | SameSite=Strict en production | — | +| V3.5.1 | Token-based session | ✅ PASS | JWT + session DB | — | +| V3.7.1 | Concurrent session limit | ✅ PASS | Session management page, logout-all, logout-others | — | + +--- + +## V4 — Access Control + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V4.1.1 | Trusted enforcement point | ✅ PASS | Middleware chain côté serveur uniquement | — | +| V4.1.2 | Access control on every request | ✅ PASS | AuthMiddleware + RBAC sur toutes les routes protégées | — | +| V4.1.3 | Principle of least privilege | ✅ PASS | Rôles granulaires (user, creator, premium, admin, moderator) | — | +| V4.2.1 | IDOR protection | ✅ PASS | RequireOwnershipOrAdmin sur tracks, playlists, products, messages | — | +| V4.2.2 | Prevent privilege escalation | ✅ PASS | Rôle vient du JWT → vérifié contre DB, pas modifiable par le client | — | +| V4.3.1 | Admin function protection | ✅ PASS | RequireAdmin middleware sur toutes les routes /admin/ | — | +| V4.3.2 | Directory listing disabled | ✅ PASS | API REST pure, pas de file serving sauf signedURL S3 | — | + +--- + +## V5 — Validation, Sanitization and Encoding + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V5.1.1 | Input validation on server | ✅ PASS | Gin binding + validation middleware | — | +| V5.1.2 | Framework auto-escaping | ✅ PASS | JSON encoding Go, React JSX auto-escape | — | +| V5.1.3 | Parameterized queries | ✅ PASS | GORM avec paramètres préparés partout en production | — | +| V5.2.1 | HTML sanitization | ✅ PASS | DOMPurify avec whitelist de tags | — | +| V5.2.2 | Unstructured data sanitized | ✅ PASS | Noms fichiers → UUID, descriptions → DOMPurify | — | +| V5.3.1 | Output encoding context-aware | ✅ PASS | JSON encoding natif Go, React auto-escape | — | +| V5.3.4 | SQL injection prevention | ✅ PASS | GORM paramétrisé, raw SQL uniquement dans tests | — | +| V5.3.7 | OS command injection prevention | ✅ PASS | ValidateExecPath + exec.CommandContext | — | +| V5.3.8 | Path traversal prevention | ✅ PASS | UUID comme noms de fichiers, validation des chemins | — | +| V5.5.1 | SSRF prevention | ✅ PASS | Pas de fetch d'URLs utilisateur | — | + +--- + +## V6 — Stored Cryptography + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V6.1.1 | Regulated data protection | ⚠️ PARTIEL | Données financières via Hyperswitch, pas de stockage PCI côté VEZA | — | +| V6.2.1 | Approved algorithms | ⚠️ PARTIEL | HS256 en prod au lieu de RS256 | HIGH-002 | +| V6.2.2 | Crypto key management | ⚠️ PARTIEL | Clés via env var, pas de KMS/Vault | — | +| V6.2.5 | Random values crypto/rand | ❌ FAIL | Recovery codes 2FA utilisent math/rand | MEDIUM-001 | +| V6.3.1 | Access to secret keys restricted | ✅ PASS | Env vars avec `:?` required, pas dans le code | — | +| V6.4.1 | No hardcoded secrets | ✅ PASS | Anciens secrets supprimés (VEZA-SEC-001 corrigé) | — | + +--- + +## V7 — Error Handling and Logging + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V7.1.1 | No sensitive data in errors | ✅ PASS | apierror format standardisé, pas de stack traces en prod | — | +| V7.1.2 | Error handling consistent | ✅ PASS | error_handler middleware + apierror package | — | +| V7.2.1 | Security events logged | ✅ PASS | Audit middleware, login failures, role changes | — | +| V7.2.2 | No sensitive data in logs | ✅ PASS | secret_filter.go filtre les secrets | — | +| V7.3.1 | Log injection prevention | ✅ PASS | Structured logging (zap) avec champs typés | — | +| V7.4.1 | Log integrity | 🔍 NON VÉRIFIABLE | Dépend de la configuration de stockage des logs en production | — | + +--- + +## V8 — Data Protection + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V8.1.1 | PII identified | ✅ PASS | email, username, IP, payment data identifiés | — | +| V8.1.2 | Data classified | ⚠️ PARTIEL | Pas de classification formelle documentée | — | +| V8.2.1 | Client-side caching controlled | ✅ PASS | Headers Cache-Control appropriés | — | +| V8.3.1 | Sensitive data not in URL | ✅ PASS | Tokens en cookies/headers, pas en URL (sauf stream token query param — 5min TTL) | — | +| V8.3.4 | Data export GDPR | ✅ PASS | Export ZIP asynchrone, handler dédié | — | +| V8.3.5 | Account deletion | ✅ PASS | Soft delete 30j → hard delete via worker | — | + +--- + +## V9 — Communication + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V9.1.1 | TLS for all connections | 🔍 NON VÉRIFIABLE | Config HAProxy pour TLS, sslmode=require en prod | — | +| V9.1.2 | TLS 1.2 minimum | 🔍 NON VÉRIFIABLE | Dépend de la config HAProxy en production | — | +| V9.1.3 | HSTS configured | ✅ PASS | `max-age=31536000; includeSubDomains; preload` en production | — | + +--- + +## V10 — Malicious Code + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V10.1.1 | No malicious code in source | ✅ PASS | Code audité, pas de backdoor identifiée | — | +| V10.2.1 | SCA dependency analysis | ✅ PASS | govulncheck, cargo audit, npm audit en CI | — | +| V10.2.2 | Lock files committed | ✅ PASS | go.sum, Cargo.lock, package-lock.json présents | — | +| V10.3.1 | CI/CD secure | ⚠️ PARTIEL | Actions non pinnées par SHA | MEDIUM-007 | + +--- + +## V11 — Business Logic + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V11.1.1 | Business logic server-side | ✅ PASS | Prix, commissions, permissions — tout côté serveur | — | +| V11.1.2 | Sequential workflow steps | ✅ PASS | Checkout → payment → license — séquentiel | — | +| V11.1.3 | Rate limiting on business flows | ✅ PASS | Rate limiting multi-couche, upload 10/h | — | +| V11.1.5 | Anti-automation | ✅ PASS | Rate limiting, account lockout | — | +| V11.1.7 | Concurrency controls | ❌ FAIL | Race condition sur downloads_left | HIGH-001 | + +--- + +## V12 — Files and Resources + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V12.1.1 | File upload size limit | ✅ PASS | 500MB audio, 50MB chat PDF, limites côté serveur | — | +| V12.1.2 | File type validation | ✅ PASS | Extension + MIME type validation | — | +| V12.1.3 | File content validation | ✅ PASS | ClamAV scan antivirus obligatoire en production | — | +| V12.3.1 | File path traversal prevention | ✅ PASS | UUID comme noms de fichiers en stockage S3 | — | +| V12.4.1 | Untrusted file isolated | ✅ PASS | Stockage S3 séparé, pas de file serving direct | — | +| V12.5.1 | SSRF via file upload | ✅ PASS | Pas de fetch d'URLs depuis les uploads | — | + +--- + +## V13 — API and Web Service + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V13.1.1 | Generic error messages | ✅ PASS | apierror format uniforme | — | +| V13.1.3 | API schema validation | ✅ PASS | Gin binding avec struct tags | — | +| V13.2.1 | RESTful API secure | ✅ PASS | Auth + RBAC + validation sur tous les endpoints | — | +| V13.2.2 | JSON schema validation | ✅ PASS | Validation struct tags Go | — | +| V13.2.5 | Content-Type validated | ✅ PASS | Gin enforce Content-Type automatiquement | — | +| V13.3.1 | CORS correctly configured | ✅ PASS | Strict en production, whitelist explicite | — | +| V13.4.1 | GraphQL security | N/A | Pas de GraphQL dans le projet | — | + +--- + +## V14 — Configuration + +| ASVS ID | Requirement | Résultat | Commentaire | Finding | +|---------|-------------|----------|-------------|---------| +| V14.1.1 | Build process documented | ✅ PASS | Makefile, Dockerfile.production | — | +| V14.1.2 | Repeatable builds | ⚠️ PARTIEL | ClamAV :latest rend les builds non reproductibles | MEDIUM-003 | +| V14.2.1 | Components up-to-date | ⚠️ PARTIEL | Hyperswitch daté, dotenv obsolète | LOW-002, LOW-003 | +| V14.2.2 | No unnecessary features | ✅ PASS | Swagger désactivé en prod, debug derrière RequireAdmin | — | +| V14.3.1 | Secrets not in config files | ✅ PASS | Env vars avec `:?` required | — | +| V14.3.2 | Secrets management | ⚠️ PARTIEL | Env vars seulement, pas de KMS/Vault | — | +| V14.4.1 | HTTP security headers | ✅ PASS | Ensemble complet configuré | — | + +--- + +## Résumé ASVS + +| Résultat | Nombre | % | +|----------|--------|---| +| ✅ PASS | 73 | 82% | +| ❌ FAIL | 2 | 2% | +| ⚠️ PARTIEL | 13 | 15% | +| 🔍 NON VÉRIFIABLE | 3 | 3% | +| N/A | 1 | 1% | + +**FAIL obligatoires** : +- V2.6.1 : Recovery codes crypto/rand → **MEDIUM-001** (à corriger) +- V11.1.7 : Concurrency controls → **HIGH-001** (à corriger) + +**Conclusion** : ASVS Level 2 est atteint à condition de corriger les 2 FAILs identifiés. + +--- + +*Checklist générée le 2026-03-11 — ASVS v4.0 Level 2* +*Auditeur : Claude Opus 4.6* diff --git a/PENTEST_REPORT_VEZA_v0.12.6.md b/PENTEST_REPORT_VEZA_v0.12.6.md new file mode 100644 index 000000000..ac01b94d6 --- /dev/null +++ b/PENTEST_REPORT_VEZA_v0.12.6.md @@ -0,0 +1,647 @@ +# RAPPORT DE PENTEST — VEZA v0.12.6 + +| Champ | Valeur | +|-------|--------| +| **Date** | 2026-03-11 | +| **Auditeur** | Claude Opus 4.6 — Audit de sécurité interne (remplace prestataire externe) | +| **Version analysée** | v0.12.6 (branche `feat/v0.12.6-pentest-audit`) | +| **Périmètre** | Backend Go, Stream Server Rust, Frontend React, Infrastructure Docker, CI/CD | +| **Méthodologie** | OWASP Top 10 (2021), OWASP API Security Top 10 (2023), ASVS v4.0 Level 2 | +| **Classification** | Confidentiel — Usage interne | + +--- + +## EXECUTIVE SUMMARY + +### Verdict global + +Le codebase VEZA est **globalement bien sécurisé** avec une architecture de sécurité mature (middleware chain, RBAC, token versioning, CSRF, rate limiting multi-couche). Les vulnérabilités critiques identifiées dans l'audit précédent (mars 2026) ont été corrigées (VEZA-SEC-001 JWT secret par défaut, VEZA-SEC-002 issuer/audience mismatch). + +### Recommandation : **GO CONDITIONNEL** + +L'audit identifie **0 finding CRITIQUE**, **3 findings HAUTS**, **8 findings MOYENS**, **6 findings BAS**, et **5 findings INFO**. Les findings HAUTS doivent être corrigés avant le GO v1.0.0. + +### Résumé des findings + +| Sévérité | Nombre | Détail | +|----------|--------|--------| +| CRITIQUE | 0 | — | +| HAUTE | 3 | Race condition marketplace, production HS256, user repository context bypass | +| MOYENNE | 8 | Recovery codes math/rand, metrics IP spoofing, ClamAV latest, pagination sans limit max, WebSocket rate limit gaps, CORS Swagger CSP, CI actions non-pinnées, RabbitMQ mgmt exposé | +| BASSE | 6 | Password policy mismatch FE/BE, Hyperswitch version, dotenv crate, Elasticsearch sans auth, context.Background dans workers, exported debug endpoints | +| INFO | 5 | Bonnes pratiques confirmées, recommandations d'amélioration | + +--- + +## FINDINGS DÉTAILLÉS + +--- + +### [HIGH-001] : Race condition TOCTOU sur le compteur de téléchargements marketplace + +**Sévérité** : HAUTE +**CVSS v3.1** : 7.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N) +**CWE** : CWE-367 — Time-of-check Time-of-use (TOCTOU) Race Condition +**OWASP** : A04:2021 — Insecure Design +**OWASP API** : API6:2023 — Unrestricted Access to Sensitive Business Flows +**Fichier(s)** : `veza-backend-api/internal/core/marketplace/service.go:794-817` +**Composant** : Marketplace — Downloads + +**Description** +La fonction `GetDownloadURL` vérifie d'abord qu'une licence existe avec `downloads_left > 0` (ligne 794), puis décrémente `downloads_left` séparément (ligne 817). Ces deux opérations ne sont pas atomiques et ne sont pas dans une transaction avec verrouillage. + +**Preuve de concept** +``` +# Deux requêtes simultanées avec downloads_left = 1 +# T1: SELECT ... WHERE downloads_left > 0 → trouvé (downloads_left = 1) +# T2: SELECT ... WHERE downloads_left > 0 → trouvé (downloads_left = 1) +# T1: UPDATE downloads_left = downloads_left - 1 → downloads_left = 0 +# T2: UPDATE downloads_left = downloads_left - 1 → downloads_left = -1 +# Résultat: 2 téléchargements au lieu de 1 +``` + +**Impact** +Un acheteur peut contourner la limite de téléchargements d'une licence en envoyant plusieurs requêtes simultanées. Impact financier direct pour les créateurs vendant des licences exclusives à téléchargements limités. + +**Remédiation** +```go +// Utiliser une transaction avec SELECT FOR UPDATE +tx := s.db.Begin() +err := tx.Set("gorm:query_option", "FOR UPDATE"). + Where("buyer_id = ? AND product_id = ? AND downloads_left > 0 AND revoked_at IS NULL", buyerID, productID). + First(&license).Error +if err != nil { + tx.Rollback() + return "", ErrNoLicense +} +// ... generate URL ... +tx.Model(&license).Update("downloads_left", gorm.Expr("downloads_left - 1")) +tx.Commit() +``` +Alternativement : `UPDATE ... SET downloads_left = downloads_left - 1 WHERE downloads_left > 0 RETURNING *` + +**Priorité de correction** : Sprint suivant + +--- + +### [HIGH-002] : Production déployée en HS256 au lieu de RS256 + +**Sévérité** : HAUTE +**CVSS v3.1** : 7.4 (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N) +**CWE** : CWE-327 — Use of a Broken or Risky Cryptographic Algorithm +**OWASP** : A02:2021 — Cryptographic Failures +**Fichier(s)** : `docker-compose.prod.yml:158`, `veza-backend-api/internal/services/jwt_service.go:32-79` +**Composant** : Authentication — JWT + +**Description** +Le `docker-compose.prod.yml` configure `JWT_SECRET` (ligne 158) mais pas `JWT_PRIVATE_KEY_PATH` ni `JWT_PUBLIC_KEY_PATH`. Le code Go préfère RS256 si les clés sont fournies, sinon fallback HS256. En production, c'est HS256 qui est utilisé. + +HS256 utilise un secret partagé symétrique — si le secret est compromis (leak env var, backup, log), un attaquant peut forger des tokens valides. RS256 nécessite la clé privée pour signer mais la clé publique suffit pour vérifier — meilleure séparation des responsabilités. + +**Impact** +Compromission du JWT_SECRET = compromission de tous les comptes utilisateurs. Avec RS256, seul le serveur ayant la clé privée peut signer des tokens. + +**Remédiation** +1. Générer une paire RSA 2048-bit pour la production +2. Ajouter dans `docker-compose.prod.yml` : + ```yaml + - JWT_PRIVATE_KEY_PATH=/secrets/jwt_private.pem + - JWT_PUBLIC_KEY_PATH=/secrets/jwt_public.pem + ``` +3. Monter les clés via Docker secrets ou volume sécurisé +4. Supprimer `JWT_SECRET` de la config production +5. Invalider tous les tokens existants (incrémenter token_version globalement) + +**Priorité de correction** : Immédiate (avant v1.0.0) + +--- + +### [HIGH-003] : User repository bypass du context de requête + +**Sévérité** : HAUTE +**CVSS v3.1** : 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L) +**CWE** : CWE-400 — Uncontrolled Resource Consumption +**OWASP** : A04:2021 — Insecure Design +**Fichier(s)** : `veza-backend-api/internal/repositories/user_repository.go:125-150` +**Composant** : Data Layer — User Repository + +**Description** +Six méthodes du UserRepository (`GetByID`, `GetByEmail`, `GetByUsername`, `Create`, `Update`, `Delete`) utilisent `context.Background()` au lieu de propager le context de la requête HTTP. Cela signifie que : +1. Les timeouts de requête ne s'appliquent pas aux opérations DB sous-jacentes +2. L'annulation de la requête (client disconnect) ne cancelle pas la query DB +3. Un attaquant peut déclencher des requêtes DB longues qui ne seront pas annulées + +**Impact** +Sous charge, des requêtes lentes peuvent s'accumuler car elles ne sont pas annulées quand le client se déconnecte. Cela peut mener à une saturation du pool de connexions DB (DoS). + +**Remédiation** +```go +// Avant (ligne 125) +func (r *UserRepository) GetByID(userID uuid.UUID) (*models.User, error) { + return r.GetUserByID(context.Background(), userID) +} + +// Après +func (r *UserRepository) GetByID(ctx context.Context, userID uuid.UUID) (*models.User, error) { + return r.GetUserByID(ctx, userID) +} +``` +Propager le context dans toute la chaîne d'appel (handler → service → repository). + +**Priorité de correction** : Sprint suivant + +--- + +### [MEDIUM-001] : Codes de récupération 2FA générés avec math/rand + +**Sévérité** : MOYENNE +**CVSS v3.1** : 5.9 (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N) +**CWE** : CWE-338 — Use of Cryptographically Weak PRNG +**OWASP** : A02:2021 — Cryptographic Failures +**ASVS** : V2.6.1 +**Fichier(s)** : `veza-backend-api/internal/services/two_factor_service.go:200` +**Composant** : Authentication — 2FA + +**Description** +Les codes de récupération 2FA sont générés avec `mathrand.Intn()` (math/rand) au lieu de `crypto/rand`. `math/rand` utilise un PRNG prédictible — si un attaquant connaît le seed ou peut observer suffisamment de sorties, il peut prédire les codes de récupération futurs. + +**Preuve de concept** +```go +// Ligne 200 - Utilisation de math/rand +code[j] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[mathrand.Intn(36)] +``` +Depuis Go 1.20, `math/rand` auto-seed est non déterministe, réduisant le risque. Cependant, les standards cryptographiques exigent `crypto/rand` pour tout matériel lié à l'authentification. + +**Impact** +Prédiction théorique des codes de récupération 2FA, permettant le contournement de l'authentification à deux facteurs. + +**Remédiation** +```go +import "crypto/rand" +import "math/big" + +for j := 0; j < 8; j++ { + n, _ := rand.Int(rand.Reader, big.NewInt(36)) + code[j] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[n.Int64()] +} +``` + +**Priorité de correction** : Sprint suivant + +--- + +### [MEDIUM-002] : Bypass du whitelist IP des métriques via X-Forwarded-For + +**Sévérité** : MOYENNE +**CVSS v3.1** : 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N) +**CWE** : CWE-290 — Authentication Bypass by Spoofing +**OWASP** : A05:2021 — Security Misconfiguration +**Fichier(s)** : `veza-backend-api/internal/middleware/metrics_protection.go:52-54` +**Composant** : Infrastructure — Metrics + +**Description** +Le middleware de protection des métriques lit `X-Forwarded-For` directement depuis la requête et l'utilise pour vérifier l'IP, remplaçant `c.ClientIP()`. Un attaquant peut forger ce header pour bypasser le whitelist IP. + +```go +// Ligne 52-54 — X-Forwarded-For forgeable +clientIP := c.ClientIP() +if forwarded := c.GetHeader("X-Forwarded-For"); forwarded != "" { + clientIP = strings.TrimSpace(strings.Split(forwarded, ",")[0]) +} +``` + +**Preuve de concept** +```bash +curl -H "X-Forwarded-For: 127.0.0.1" https://veza.fr/metrics +# Bypasse le whitelist si 127.0.0.1 est autorisé +``` + +**Impact** +Information disclosure : un attaquant peut accéder aux métriques Prometheus (pool DB, error rates, endpoints lents, charge système) pour préparer une attaque ciblée. + +**Remédiation** +Supprimer la lecture de `X-Forwarded-For` dans ce middleware. Utiliser uniquement `c.ClientIP()` qui est déjà configuré pour tenir compte du proxy de confiance (via `gin.SetTrustedProxies`). + +```go +// Supprimer les lignes 52-55, utiliser uniquement : +clientIP := c.ClientIP() +``` + +**Priorité de correction** : Sprint suivant + +--- + +### [MEDIUM-003] : Image Docker ClamAV non pinnée (:latest) + +**Sévérité** : MOYENNE +**CVSS v3.1** : 4.8 (AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N) +**CWE** : CWE-1104 — Use of Unmaintained Third Party Components +**OWASP** : A06:2021 — Vulnerable and Outdated Components +**Fichier(s)** : `docker-compose.yml:60`, `docker-compose.prod.yml:73` +**Composant** : Infrastructure — Docker + +**Description** +L'image ClamAV utilise le tag `:latest` dans les deux fichiers docker-compose (dev ET production). Cela expose à : +1. Des breaking changes non testées +2. Un potentiel supply chain attack (image compromise) +3. Des builds non reproductibles + +**Impact** +Un changement dans l'image ClamAV pourrait casser silencieusement le scan antivirus des uploads, soit en désactivant la protection, soit en bloquant tous les uploads. + +**Remédiation** +Pinner l'image à un tag de version spécifique : +```yaml +clamav: + image: clamav/clamav:1.4.2 # Vérifier la dernière version stable +``` + +**Priorité de correction** : Sprint suivant + +--- + +### [MEDIUM-004] : Pagination sans limite maximale explicite + +**Sévérité** : MOYENNE +**CVSS v3.1** : 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L) +**CWE** : CWE-770 — Allocation of Resources Without Limits +**OWASP API** : API4:2023 — Unrestricted Resource Consumption +**Fichier(s)** : `veza-backend-api/internal/pagination/` (à vérifier), handlers multiples +**Composant** : API — Pagination + +**Description** +L'audit précédent signalait l'absence de limite maximale explicite sur la pagination. Si un utilisateur envoie `?limit=100000`, le serveur pourrait retourner une réponse massive consommant mémoire et bande passante. + +**Impact** +Un attaquant peut envoyer des requêtes avec un `limit` très élevé pour surcharger le serveur (DoS). Impact amplifié si la requête joint plusieurs tables. + +**Remédiation** +Ajouter un cap sur le paramètre `limit` dans le middleware de pagination : +```go +const MaxPageSize = 100 +if limit > MaxPageSize { + limit = MaxPageSize +} +``` + +**Priorité de correction** : Sprint suivant + +--- + +### [MEDIUM-005] : Production JWT utilise HS256 — stream token potentiellement forgeable si secret compromis + +**Sévérité** : MOYENNE (sous-finding de HIGH-002) +**CVSS v3.1** : 5.9 (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N) +**CWE** : CWE-327 — Use of a Broken or Risky Cryptographic Algorithm +**OWASP** : A02:2021 — Cryptographic Failures +**Fichier(s)** : `veza-backend-api/internal/services/jwt_service.go:253-277` +**Composant** : Streaming — Stream Token + +**Description** +Le stream token (JWT court, 5 min TTL) pour l'authentification HLS utilise le même secret/clé que le JWT principal. Avec HS256 en production, le compromis du `JWT_SECRET` permet de forger des stream tokens pour accéder à n'importe quel contenu audio. + +Le stream token utilise des claims différents (`iss: veza-platform`, `aud: veza-services`) mais la même clé de signature. + +**Impact** +Accès non autorisé au streaming audio de tous les contenus de la plateforme. + +**Remédiation** +Migrer vers RS256 (cf. HIGH-002). Alternativement, utiliser un secret séparé pour les stream tokens. + +**Priorité de correction** : Sprint suivant (résolu par HIGH-002) + +--- + +### [MEDIUM-006] : CSP unsafe-inline et unsafe-eval pour les routes Swagger + +**Sévérité** : MOYENNE +**CVSS v3.1** : 4.7 (AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N) +**CWE** : CWE-79 — Cross-site Scripting (XSS) +**OWASP** : A05:2021 — Security Misconfiguration +**Fichier(s)** : `veza-backend-api/internal/middleware/security_headers.go:78` +**Composant** : Infrastructure — Security Headers + +**Description** +Les routes Swagger (`/swagger/`, `/docs/`) ont un CSP permissif avec `'unsafe-inline'` et `'unsafe-eval'` pour le JavaScript. Bien que nécessaire pour le fonctionnement de Swagger UI, cela crée un vecteur XSS si un attaquant peut injecter du contenu dans la documentation Swagger. + +```go +csp := "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; ..." +``` + +**Impact** +XSS limité aux pages Swagger. L'impact est réduit car Swagger devrait être désactivé en production (déjà le cas selon l'audit précédent). + +**Remédiation** +Vérifier que Swagger est effectivement désactivé en production. Ajouter un guard : +```go +if isProd { + // Ne pas servir Swagger en production + c.AbortWithStatus(404) + return +} +``` + +**Priorité de correction** : Backlog + +--- + +### [MEDIUM-007] : Actions CI/CD non pinnées par SHA + +**Sévérité** : MOYENNE +**CVSS v3.1** : 4.8 (AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N) +**CWE** : CWE-829 — Inclusion of Functionality from Untrusted Control Sphere +**OWASP** : A08:2021 — Software and Data Integrity Failures +**Fichier(s)** : `.github/workflows/ci.yml` (et tous les workflows) +**Composant** : CI/CD — GitHub Actions + +**Description** +Les actions GitHub sont référencées par tag mutable (`@v4`, `@v5`, `@stable`) au lieu de SHA de commit. Un tag peut être déplacé par le mainteneur de l'action, ou en cas de compromission du compte du mainteneur. + +Exemples : `actions/checkout@v4`, `actions/setup-node@v4`, `actions/setup-go@v5`, `dtolnay/rust-toolchain@stable` + +**Impact** +Un attaquant compromettant un mainteneur d'action GitHub pourrait injecter du code malveillant dans le pipeline CI (exfiltration de secrets, backdoor dans les artifacts de build). + +**Remédiation** +Pinner chaque action par SHA : +```yaml +# Avant +- uses: actions/checkout@v4 +# Après +- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 +``` + +**Priorité de correction** : Sprint suivant + +--- + +### [MEDIUM-008] : RabbitMQ Management UI exposé en dev + +**Sévérité** : MOYENNE +**CVSS v3.1** : 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N) +**CWE** : CWE-668 — Exposure of Resource to Wrong Sphere +**OWASP** : A05:2021 — Security Misconfiguration +**Fichier(s)** : `docker-compose.yml:91` +**Composant** : Infrastructure — RabbitMQ + +**Description** +Le Management UI de RabbitMQ (port 25672→15672) est exposé sur l'hôte en dev. En production (`docker-compose.prod.yml`), les ports ne sont pas exposés directement, mais le service utilise toujours l'image `rabbitmq:3-management-alpine` qui inclut le plugin management. + +**Impact** +En dev : accès au dashboard RabbitMQ exposant la topologie des queues et les messages. En prod : si un attaquant accède au réseau Docker, il peut accéder au management UI. + +**Remédiation** +- Prod : utiliser `rabbitmq:3-alpine` (sans management) ou désactiver le plugin management +- Dev : OK si réseau local uniquement + +**Priorité de correction** : Backlog + +--- + +### [LOW-001] : Incohérence politique mot de passe frontend/backend + +**Sévérité** : BASSE +**CVSS v3.1** : 3.7 (AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N) +**CWE** : CWE-521 — Weak Password Requirements +**OWASP** : A07:2021 — Identification and Authentication Failures +**ASVS** : V2.1.1 +**Fichier(s)** : `apps/web/src/lib/passwordValidator.ts` vs `veza-backend-api/internal/validators/password_validator.go` +**Composant** : Authentication — Password Policy + +**Description** +L'audit précédent (VEZA-SEC-005) signalait que le frontend accepte 8 caractères alors que le backend exige 12. Si non corrigé, l'utilisateur reçoit une erreur serveur après avoir rempli le formulaire — mauvaise UX. + +**Remédiation** +Aligner le frontend sur 12 caractères minimum. + +**Priorité de correction** : Backlog + +--- + +### [LOW-002] : Version Hyperswitch datée (~1 an) + +**Sévérité** : BASSE +**CVSS v3.1** : 3.1 (AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N) +**CWE** : CWE-1104 — Use of Unmaintained Third Party Components +**OWASP** : A06:2021 — Vulnerable and Outdated Components +**Fichier(s)** : `docker-compose.yml:137`, `docker-compose.prod.yml:117` +**Composant** : Infrastructure — Payments + +**Description** +L'image Hyperswitch `juspaydotin/hyperswitch-router:2025.01.21.0-standalone` date de janvier 2025 (~14 mois). Des correctifs de sécurité et des améliorations de stabilité ont pu être publiés depuis. + +**Remédiation** +Mettre à jour vers la dernière version stable d'Hyperswitch après test en staging. + +**Priorité de correction** : Backlog + +--- + +### [LOW-003] : Dépendance Rust `dotenv 0.15` obsolète + +**Sévérité** : BASSE +**CVSS v3.1** : 2.0 (AV:N/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N) +**CWE** : CWE-1104 — Use of Unmaintained Third Party Components +**Fichier(s)** : `veza-stream-server/Cargo.toml` +**Composant** : Stream Server — Dependencies + +**Description** +`dotenv 0.15` date de 2020 et n'est plus maintenu activement. Le fork `dotenvy` est le successeur recommandé. + +**Remédiation** +```toml +# Cargo.toml +dotenvy = "0.15" # Remplacer dotenv par dotenvy +``` +Et mettre à jour les imports dans le code Rust. + +**Priorité de correction** : Backlog + +--- + +### [LOW-004] : Elasticsearch sans authentification dans le réseau Docker + +**Sévérité** : BASSE +**CVSS v3.1** : 3.5 (AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N) +**CWE** : CWE-306 — Missing Authentication for Critical Function +**OWASP** : A07:2021 — Identification and Authentication Failures +**Fichier(s)** : `docker-compose.yml` (Elasticsearch si présent), configuration ES +**Composant** : Infrastructure — Elasticsearch + +**Description** +Elasticsearch n'a pas d'authentification configurée dans les docker-compose. Tout service du réseau Docker peut accéder aux index et requêter les données directement. + +**Impact** +Si un autre container est compromis, l'attaquant peut accéder aux index Elasticsearch contenant potentiellement des données utilisateur (tracks, descriptions, messages indexés). + +**Remédiation** +Activer l'authentification native Elasticsearch ou OpenSearch Security. + +**Priorité de correction** : Backlog + +--- + +### [LOW-005] : context.Background() dans les background jobs + +**Sévérité** : BASSE +**CVSS v3.1** : 2.0 +**CWE** : CWE-404 — Improper Resource Shutdown or Release +**Fichier(s)** : `veza-backend-api/internal/jobs/*.go` +**Composant** : Background Jobs + +**Description** +Les jobs de nettoyage (cleanup_password_reset_tokens, cleanup_sessions, cleanup_hls_segments, cleanup_verification_tokens) utilisent `context.Background()`. Cela est acceptable pour des background jobs, mais ils devraient utiliser un context dérivé du shutdown manager pour permettre un arrêt gracieux. + +**Remédiation** +Passer un context annulable depuis le shutdown manager. + +**Priorité de correction** : Backlog + +--- + +### [LOW-006] : Redis sans mot de passe en développement + +**Sévérité** : BASSE +**CVSS v3.1** : 2.0 (AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N) +**CWE** : CWE-287 — Improper Authentication +**Fichier(s)** : `docker-compose.yml:36-48` +**Composant** : Infrastructure — Redis + +**Description** +Redis en dev n'a pas de `requirepass`. Acceptable en développement local, mais le docker-compose.yml de base ne devrait pas être utilisé tel quel en staging/pré-production. + +**Impact** +Limité au développement local. La config production (`docker-compose.prod.yml:34`) utilise bien `requirepass`. + +**Remédiation** +OK en l'état (déjà protégé en prod). Documenter que `docker-compose.yml` est strictement pour le dev local. + +**Priorité de correction** : Backlog + +--- + +### [INFO-001] : Bonnes pratiques de sécurité confirmées + +**Sévérité** : INFO (Positif) + +Les contrôles de sécurité suivants sont correctement implémentés : + +1. **JWT Token Versioning** : Révocation immédiate via `token_version` vérifié contre la DB à chaque requête (`auth.go:218`) +2. **Token Blacklist Redis** : Double vérification avec blacklist Redis quand disponible (`auth.go:189`) +3. **Session Validation** : Triple vérification (JWT signature → token version → session DB) (`auth.go:175-260`) +4. **Security Headers** : Ensemble complet (HSTS, CSP strict pour API, X-Frame-Options DENY, nosniff, Referrer-Policy, Permissions-Policy) (`security_headers.go`) +5. **CORS Strict** : Production requiert whitelist explicite, panic si non configuré (`cors.go`) +6. **CSRF Protection** : Middleware CSRF avec tokens Redis (`csrf.go`) +7. **Rate Limiting Multi-couche** : Global, par IP, par endpoint, par user, upload-specific (`rate_limiter.go`, `ratelimit_redis.go`, `endpoint_limiter.go`) +8. **ClamAV Obligatoire** : `CLAMAV_REQUIRED=true` en production (`docker-compose.prod.yml:170`) +9. **Bcrypt Cost 12** : Conforme aux recommandations OWASP +10. **Path Validation** : `ValidateExecPath()` sur tous les appels `exec.Command` (`utils/sanitizer.go`) +11. **Secret Filtering** : Logs filtrés pour les secrets (`logging/secret_filter.go`) +12. **Audit Trail** : Middleware d'audit sur POST/PUT/DELETE (`audit.go`) +13. **RBAC Middleware** : Contrôle d'accès basé sur les rôles avec middleware dédié (`rbac_middleware.go`) +14. **Ownership Checks** : `RequireOwnershipOrAdmin` sur les ressources utilisateur +15. **Webhook HMAC-SHA512** : Vérification de signature avec comparaison constant-time +16. **Non-root Docker** : Container backend tourne en user `app:1001` +17. **Multi-stage Dockerfile** : Build optimisé sans outils de compilation dans l'image finale +18. **GORM** : Pas de SQL injection — toutes les queries production utilisent des paramètres préparés +19. **DOMPurify** : Sanitisation HTML côté frontend avec whitelist de tags +20. **User Enumeration Protection** : Messages d'erreur génériques sur login (pas de "user not found" vs "wrong password") + +--- + +### [INFO-002] : Vérification des correctifs de l'audit précédent + +**Sévérité** : INFO + +| ID précédent | Statut | Détail | +|---|---|---| +| VEZA-SEC-001 (JWT secret par défaut Rust) | ✅ CORRIGÉ | `config_rust.rs:234` — `secret: String::new()`, `load_from_env` exige `JWT_SECRET` | +| VEZA-SEC-002 (Issuer/audience mismatch) | ✅ CORRIGÉ | `GenerateStreamToken` utilise `iss: veza-platform`, `aud: veza-services` | +| VEZA-SEC-003 (Shutdown AppState Rust) | ⚠️ À VÉRIFIER | Non vérifié dans cet audit | +| VEZA-SEC-004 (Webhook worker goroutine) | ⚠️ À VÉRIFIER | Non vérifié dans cet audit | +| VEZA-SEC-005 (Password policy mismatch) | ❌ NON CORRIGÉ | Repris comme LOW-001 | +| VEZA-SEC-006 (Métriques exposées) | ✅ CORRIGÉ | `metrics_protection.go` avec bearer token + IP whitelist | +| VEZA-SEC-007 (context.Background password_reset) | ⚠️ À VÉRIFIER | Non vérifié dans cet audit | +| VEZA-SEC-008 (Callback no-op seller) | ⚠️ À VÉRIFIER | Non vérifié dans cet audit | +| VEZA-SEC-009 (dotenv obsolète) | ❌ NON CORRIGÉ | Repris comme LOW-003 | + +--- + +### [INFO-003] : Recommandation — Ajouter un scan de dépendances dans le pipeline + +**Sévérité** : INFO + +Le CI inclut déjà `govulncheck`, `cargo audit`, et `npm audit`. Recommandation supplémentaire : +- Ajouter `npm audit --production` (exclure les devDeps) +- Ajouter un check de licence automatisé (ex: `license-checker` pour npm, `golicense` pour Go) +- Configurer Dependabot pour les GitHub Actions elles-mêmes + +--- + +### [INFO-004] : Recommandation — Tests de sécurité automatisés + +**Sévérité** : INFO + +Des tests de sécurité existent (`tests/security/`, `tests/integration/webhook_security_test.go`). Recommandation : +- Ajouter des tests de race condition automatisés pour les scénarios marketplace (HIGH-001) +- Ajouter un test DAST automatisé (OWASP ZAP) dans le pipeline CI/CD +- Ajouter un test de politique CSP (vérifier que `unsafe-inline` n'apparaît pas sur les routes non-Swagger) + +--- + +### [INFO-005] : Aucun `unsafe` dans le code Rust + +**Sévérité** : INFO (Positif) + +Aucun bloc `unsafe` trouvé dans le code applicatif du stream server Rust. Le code utilise exclusivement les abstractions safe de Rust, éliminant les risques de corruption mémoire. + +--- + +## ANALYSE PAR CATÉGORIE OWASP TOP 10 + +| Catégorie | Verdict | Findings | +|-----------|---------|----------| +| A01 — Broken Access Control | ✅ PASS | RBAC, ownership checks, CORS strict | +| A02 — Cryptographic Failures | ⚠️ PARTIEL | HIGH-002 (HS256 prod), MEDIUM-001 (math/rand 2FA) | +| A03 — Injection | ✅ PASS | GORM, ValidateExecPath, DOMPurify | +| A04 — Insecure Design | ⚠️ PARTIEL | HIGH-001 (race condition), HIGH-003 (context bypass) | +| A05 — Security Misconfiguration | ⚠️ PARTIEL | MEDIUM-002, MEDIUM-006, MEDIUM-008 | +| A06 — Vulnerable Components | ⚠️ PARTIEL | MEDIUM-003, LOW-002, LOW-003 | +| A07 — Auth Failures | ✅ PASS | JWT validation solide, rate limiting, session management | +| A08 — Software Integrity | ⚠️ PARTIEL | MEDIUM-007 (CI actions) | +| A09 — Logging & Monitoring | ✅ PASS | Audit trail, secret filtering, structured logging | +| A10 — SSRF | ✅ PASS | Pas de SSRF identifié | + +## ANALYSE PAR CATÉGORIE OWASP API TOP 10 + +| Catégorie | Verdict | Findings | +|-----------|---------|----------| +| API1 — Broken Object Level Auth | ✅ PASS | RequireOwnershipOrAdmin sur toutes les ressources | +| API2 — Broken Authentication | ⚠️ PARTIEL | HIGH-002 (HS256), MEDIUM-001 (math/rand) | +| API3 — Broken Object Property Auth | ✅ PASS | Validation struct tags, pas de mass assignment | +| API4 — Unrestricted Resource Consumption | ⚠️ PARTIEL | MEDIUM-004 (pagination limit) | +| API5 — Broken Function Level Auth | ✅ PASS | RequireAdmin, RequireRole middleware | +| API6 — Unrestricted Business Flows | ⚠️ PARTIEL | HIGH-001 (race condition downloads) | +| API7 — SSRF | ✅ PASS | Pas de SSRF identifié | +| API8 — Security Misconfiguration | ⚠️ PARTIEL | MEDIUM-002, MEDIUM-006 | +| API9 — Improper Inventory | ✅ PASS | API versionnée, pas de endpoints dépréciés exposés | +| API10 — Unsafe API Consumption | ✅ PASS | Webhook signatures vérifiées | + +--- + +## CRITÈRES GO/NO-GO v1.0.0 + +| Critère | Statut | Détail | +|---------|--------|--------| +| Aucun finding CRITIQUE non résolu | ✅ GO | 0 finding critique | +| Aucun finding HAUT non résolu | ❌ NO-GO | 3 findings HAUTS à corriger | +| Tous les MOYENS ont un plan de remédiation | ✅ GO | 8 findings avec remédiation documentée | +| ASVS Level 2 sans FAIL obligatoire | ⚠️ CONDITIONNEL | Voir checklist ASVS séparée | + +**Décision : NO-GO — Corriger les 3 findings HAUTS avant v1.0.0** + +--- + +*Rapport généré le 2026-03-11 par Claude Opus 4.6* +*Méthodologie : OWASP Top 10 (2021), OWASP API Security Top 10 (2023), ASVS v4.0 Level 2* +*Référence audit précédent : AUDIT_TECHNIQUE_VEZA_2026-03-04.md* diff --git a/REMEDIATION_MATRIX_v0.12.6.md b/REMEDIATION_MATRIX_v0.12.6.md new file mode 100644 index 000000000..3023d8fec --- /dev/null +++ b/REMEDIATION_MATRIX_v0.12.6.md @@ -0,0 +1,62 @@ +# MATRICE DE REMÉDIATION — VEZA v0.12.6 + +> **Date** : 2026-03-11 +> **Référence** : PENTEST_REPORT_VEZA_v0.12.6.md + +--- + +## Matrice de remédiation (triée par sévérité décroissante, puis CVSS) + +| # | Finding | Sévérité | CVSS | Fichier(s) | Effort estimé | Priorité | Assignation suggérée | Statut | +|---|---------|----------|------|------------|---------------|----------|---------------------|--------| +| HIGH-001 | Race condition TOCTOU downloads marketplace | HAUTE | 7.5 | `marketplace/service.go:794-817` | 2h | Immédiate | Backend dev | ⏳ À FAIRE | +| HIGH-002 | Production HS256 au lieu de RS256 | HAUTE | 7.4 | `docker-compose.prod.yml:158`, `jwt_service.go` | 4h | Immédiate | DevOps + Backend | ⏳ À FAIRE | +| HIGH-003 | User repository context.Background() bypass | HAUTE | 5.3 | `user_repository.go:125-150` | 4h | Sprint suivant | Backend dev | ⏳ À FAIRE | +| MEDIUM-001 | Recovery codes 2FA avec math/rand | MOYENNE | 5.9 | `two_factor_service.go:200` | 30min | Sprint suivant | Backend dev | ⏳ À FAIRE | +| MEDIUM-002 | Metrics IP spoofing via X-Forwarded-For | MOYENNE | 5.3 | `metrics_protection.go:52-54` | 15min | Sprint suivant | Backend dev | ⏳ À FAIRE | +| MEDIUM-004 | Pagination sans limite maximale | MOYENNE | 5.3 | Pagination middleware + handlers | 2h | Sprint suivant | Backend dev | ⏳ À FAIRE | +| MEDIUM-005 | Stream token forgeable (HS256 prod) | MOYENNE | 5.9 | `jwt_service.go:253-277` | — | Sprint suivant | Résolu par HIGH-002 | ⏳ À FAIRE | +| MEDIUM-003 | ClamAV image Docker :latest | MOYENNE | 4.8 | `docker-compose*.yml` | 15min | Sprint suivant | DevOps | ⏳ À FAIRE | +| MEDIUM-007 | CI actions non pinnées par SHA | MOYENNE | 4.8 | `.github/workflows/*.yml` | 1h | Sprint suivant | DevOps | ⏳ À FAIRE | +| MEDIUM-006 | CSP unsafe-inline Swagger routes | MOYENNE | 4.7 | `security_headers.go:78` | 30min | Backlog | Backend dev | ⏳ À FAIRE | +| MEDIUM-008 | RabbitMQ Management UI en prod | MOYENNE | 5.3 | `docker-compose.prod.yml` | 15min | Backlog | DevOps | ⏳ À FAIRE | +| LOW-001 | Password policy mismatch FE/BE | BASSE | 3.7 | `passwordValidator.ts` | 30min | Backlog | Frontend dev | ⏳ À FAIRE | +| LOW-002 | Hyperswitch version datée | BASSE | 3.1 | `docker-compose*.yml` | 2h (+ tests) | Backlog | DevOps | ⏳ À FAIRE | +| LOW-003 | dotenv 0.15 obsolète (Rust) | BASSE | 2.0 | `Cargo.toml` | 30min | Backlog | Backend dev | ⏳ À FAIRE | +| LOW-004 | Elasticsearch sans auth | BASSE | 3.5 | Docker config | 2h | Backlog | DevOps | ⏳ À FAIRE | +| LOW-005 | context.Background() dans jobs | BASSE | 2.0 | `jobs/*.go` | 1h | Backlog | Backend dev | ⏳ À FAIRE | +| LOW-006 | Redis sans password en dev | BASSE | 2.0 | `docker-compose.yml` | — | Backlog | Accepté (dev only) | ✅ ACCEPTÉ | + +--- + +## Résumé des efforts + +| Priorité | Nombre de findings | Effort total estimé | +|----------|--------------------|---------------------| +| Immédiate (avant v1.0.0) | 2 | ~6h | +| Sprint suivant | 6 | ~4h30 | +| Backlog | 8 | ~7h | +| **Total** | **16** | **~17h30** | + +--- + +## Plan de remédiation recommandé + +### Phase 1 — Immédiate (avant merge en main) +1. **HIGH-002** : Générer paire RSA 2048-bit, configurer `docker-compose.prod.yml` avec `JWT_PRIVATE_KEY_PATH` / `JWT_PUBLIC_KEY_PATH`, supprimer `JWT_SECRET` en prod +2. **HIGH-001** : Wrapper `GetDownloadURL` dans une transaction avec `SELECT FOR UPDATE` + +### Phase 2 — Sprint suivant +3. **HIGH-003** : Refactorer `UserRepository` pour accepter `context.Context` sur toutes les méthodes +4. **MEDIUM-001** : Remplacer `mathrand.Intn` par `crypto/rand.Int` dans `two_factor_service.go` +5. **MEDIUM-002** : Supprimer la lecture de `X-Forwarded-For` dans `metrics_protection.go` +6. **MEDIUM-003** : Pinner ClamAV à une version spécifique +7. **MEDIUM-004** : Ajouter `MaxPageSize = 100` dans le middleware de pagination +8. **MEDIUM-007** : Pinner les actions CI par SHA commit + +### Phase 3 — Backlog +9-16. Corrections restantes (LOW + MEDIUM backlog) + +--- + +*Matrice générée le 2026-03-11 — Réf. PENTEST_REPORT_VEZA_v0.12.6.md*