veza/docs/PENTEST_REPORT_VEZA_v0.12.6.md
senke 2a80cb4d2f feat(v0.12.6): update pentest deliverables with comprehensive 36-finding audit
Expanded from initial 14-finding analysis to full 36 findings after
6 specialized audit agents completed deep analysis.

- PENTEST_REPORT: 5 CRITICAL, 10 HIGH, 12 MEDIUM, 6 LOW, 3 INFO
- REMEDIATION_MATRIX: P0 (6h), P1 (17h), P2 (8h), P3 (10h) = ~41h total
- ASVS_CHECKLIST: 70/102 (68.6%) with 5 FAIL, 26 PARTIAL

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:52:03 +01:00

16 KiB

Rapport de Pentest — VEZA v0.12.6

Date : 2026-03-13 Auditeur : Claude Opus 4.6 (SAST + revue manuelle de code + 6 agents d'audit spécialisés) Scope : Monorepo complet — Go backend, Rust stream server, React frontend, CI/CD, infrastructure Docker Méthodologie : OWASP Top 10 2021, OWASP API Security Top 10 2023, ASVS Level 2 Référence : ORIGIN_SECURITY_FRAMEWORK.md


Résumé Exécutif

Sévérité Count
CRITICAL 5
HIGH 10
MEDIUM 12
LOW 6
INFO 3
Total findings 36
PASS (contrôles validés) 24

Posture globale : La codebase VEZA présente une architecture sécurisée avec d'excellentes fondations (JWT RS256, bcrypt, HMAC webhooks, rate limiting Redis). Cependant, l'audit approfondi révèle 5 vulnérabilités critiques — principalement des race conditions financières, des IDOR sur les analytics, et des WebSocket sans validation d'origine. Ces issues sont toutes remédiables sans refonte architecturale.


CRITICAL FINDINGS

CRIT-001 — WebSocket Cross-Site Hijacking (3 handlers)

Champ Valeur
Sévérité CRITICAL
OWASP A07:2021 — Cross-Site Request Forgery
CWE CWE-346 (Origin Validation Error)
Fichiers chat_websocket_handler.go:50, playback_websocket_handler.go:106, co_listening_websocket_handler.go:105
CVSS 8.1

Description : Les 3 handlers WebSocket utilisent InsecureSkipVerify: true dans websocket.AcceptOptions, désactivant la validation du header Origin. Un attaquant peut établir une connexion WebSocket depuis n'importe quel domaine et usurper les sessions utilisateur.

conn, err := websocket.Accept(c.Writer, c.Request, &websocket.AcceptOptions{
    InsecureSkipVerify: true, // VULNÉRABLE
})

Impact : Cross-Site WebSocket Hijacking (CSWSH) — un attaquant peut intercepter les messages chat, contrôler la lecture audio, et accéder aux sessions d'écoute collaborative.

Remédiation : Supprimer InsecureSkipVerify: true, implémenter OriginPatterns avec whitelist des domaines autorisés.


CRIT-002 — Payout Balance Race Condition (Double-Spend)

Champ Valeur
Sévérité CRITICAL
OWASP API6:2023 — Unrestricted Access to Sensitive Business Flows
CWE CWE-362 (Race Condition)
Fichier veza-backend-api/internal/core/marketplace/payout.go:175-195
CVSS 9.1

Description : RequestPayout() lit le solde hors transaction (GetSellerBalance), puis ouvre une transaction pour déduire. Entre la lecture et la déduction, une requête concurrente peut aussi lire le même solde et traiter un deuxième payout.

Scénario d'attaque : Seller avec $100 → 2 requêtes simultanées → les 2 lisent $100 → les 2 traitent $100 → $200 payés pour $100 de solde.

Remédiation : Ajouter SELECT FOR UPDATE (clause.Locking{Strength: "UPDATE"}) sur la ligne de balance DANS la transaction, avant la validation du montant.


CRIT-003 — Refund Double-Pay Race Condition

Champ Valeur
Sévérité CRITICAL
CWE CWE-362
Fichier marketplace/service.go:1136-1189
CVSS 8.7

Description : RefundOrder() lit l'order hors transaction, vérifie l'autorisation, puis appelle rp.Refund(). Deux requêtes concurrentes peuvent toutes les deux passer la validation et déclencher un double remboursement.

Remédiation : Wrapper la lecture + validation + refund dans une seule transaction avec SELECT FOR UPDATE sur l'order. Vérifier order.Status != "refunded" atomiquement.


CRIT-004 — Track Analytics IDOR (No Ownership Check)

Champ Valeur
Sévérité CRITICAL
OWASP API1:2023 — Broken Object Level Authorization
CWE CWE-639 (Authorization Bypass)
Fichier analytics/handler.go:727-777
CVSS 7.5

Description : GET /api/v1/analytics/tracks/:id retourne les analytics détaillées (play count, completion rate, listener data) de n'importe quelle track sans vérifier que l'utilisateur authentifié en est le créateur.

Impact : Tout utilisateur authentifié peut espionner les analytics privées de n'importe quel créateur.

Remédiation : Ajouter une vérification track.CreatorID == userID avant de retourner les analytics.


CRIT-005 — Path Traversal in Marketplace Preview Upload

Champ Valeur
Sévérité CRITICAL
CWE CWE-22 (Path Traversal)
Fichier handlers/marketplace.go:285-290
CVSS 8.8

Description : Le nom de fichier uploadé est utilisé directement dans filepath.Join sans sanitization :

destPath := filepath.Join(previewDir, file.Filename) // VULNÉRABLE

Un attaquant peut uploader un fichier avec ../../../etc/cron.d/evil pour écrire n'importe où sur le filesystem.

Remédiation : Utiliser filepath.Base(file.Filename) ou générer un UUID comme nom de fichier.


HIGH FINDINGS

HIGH-001 — IP Spoofing via X-Forwarded-For (Rate Limit Bypass)

Champ Valeur
Sévérité HIGH
OWASP API4:2023 — Unrestricted Resource Consumption
Fichier handlers/common.go:601-610
CVSS 7.5

Description : GetClientIP() lit directement X-Forwarded-For sans passer par c.ClientIP() de Gin. Permet le contournement du rate limiting.

Remédiation : Remplacer par c.ClientIP() + configurer SetTrustedProxies().


HIGH-002 — Métriques de popularité exposées dans l'API publique

Champ Valeur
Sévérité HIGH
Fichiers user_service.go:75, social_service.go:321, types/stats.go:31, social/models.go:32

Description : followers_count, following_count exposés dans les réponses publiques (PublicUserResponse, SuggestionUser). like_count exposé sur le modèle Post social.

Remédiation : Supprimer ces champs des réponses publiques. Les exposer uniquement dans le dashboard privé.


HIGH-003 — Mass Assignment / Privilege Escalation (UpdateUser)

Champ Valeur
Sévérité HIGH
CWE CWE-915 (Mass Assignment)
Fichier api/user/handler.go:75-95, api/user/service.go:188-267

Description : UpdateMe() appelle UpdateUser() qui accepte des champs Role, IsVerified, IsActive. Un utilisateur non-admin pourrait escalader ses privilèges en envoyant {"role": "admin"}.

Remédiation : Filtrer les champs autorisés par rôle. Seuls les admins peuvent modifier role, is_verified, is_active.


HIGH-004 — RTMP Callback Authentication Faible

Champ Valeur
Sévérité HIGH
CWE CWE-345
Fichier handlers/live_stream_callback.go:26-84

Description : Les callbacks Nginx-RTMP utilisent un simple header secret statique (X-RTMP-Callback-Secret) sans HMAC, sans timestamp, sans protection contre le replay.

Remédiation : Implémenter HMAC-SHA256 avec timestamp + body dans la signature.


HIGH-005 — Refresh Token TOCTOU Race Condition

Champ Valeur
Sévérité HIGH
CWE CWE-362
Fichier auth/service.go:653-707

Description : Entre Validate() et Rotate() du refresh token, une requête concurrente peut réutiliser le même token. Le RefreshLock (line 665-671) réduit la fenêtre mais ne l'élimine pas.

Remédiation : Combiner validate + rotate dans une seule transaction DB atomique.


HIGH-006 — Promo Code Counter Race Condition

Champ Valeur
Sévérité HIGH
CWE CWE-362
Fichier marketplace/service.go:464, 764-787

Description : Le used_count du promo code est incrémenté APRÈS validation mais sans garantie atomique. Deux requêtes simultanées peuvent dépasser MaxUses.

Remédiation : Effectuer validation et incrémentation dans la même transaction avec SELECT FOR UPDATE.


HIGH-007 — Stream Token Replay Attack (Rust)

Champ Valeur
Sévérité HIGH
CWE CWE-433
Fichier veza-stream-server/src/auth/token_validator.rs:100-138

Description : Les URLs de streaming signées avec HMAC-SHA256 vérifient l'expiration mais pas la réutilisation. Un attaquant peut rejouer une URL valide multiple fois avant expiration, gonflant artificiellement les analytics.

Remédiation : Ajouter un nonce ou stocker les tokens consommés dans Redis avec TTL.


HIGH-008 — Account Deletion Missing Financial Data Cascade

Champ Valeur
Sévérité HIGH
Fichier handlers/account_deletion_handler.go:75-135

Description : La suppression de compte anonymise l'utilisateur mais ne traite pas : orders (buyer), licenses, seller payouts, seller balance, seller transfers.

Remédiation : Ajouter le nettoyage GDPR pour les données financières (anonymiser plutôt que supprimer pour les obligations légales).


HIGH-009 — Webhook Amount Not Re-Validated

Champ Valeur
Sévérité HIGH
CWE CWE-1025
Fichier marketplace/service.go:610-676

Description : ProcessPaymentWebhook() ne vérifie pas que le montant payé (Hyperswitch) correspond au total de l'order. Un webhook forgé pourrait confirmer un paiement inférieur.

Remédiation : Comparer order.TotalAmount avec le montant du webhook avant de traiter.


HIGH-010 — Free Trial Reuse Not Atomic

Champ Valeur
Sévérité HIGH
CWE CWE-362
Fichier subscription/service.go:237-251

Description : La vérification du trial gratuit (previousTrialCount) est hors transaction. Deux requêtes concurrentes peuvent toutes les deux voir count = 0 et obtenir un trial.

Remédiation : Déplacer la vérification dans la transaction avec SELECT FOR UPDATE sur le user.


MEDIUM FINDINGS

MEDIUM-001 — Incohérence bcrypt cost (10 vs 12)

Fichier : auth/service.go:156, :986 | bcrypt.DefaultCost au lieu de 12

MEDIUM-002 — GitHub Actions non épinglées par SHA (12+ actions)

Fichiers : sast.yml, security-scan.yml, cd.yml, stream-ci.yml, container-scan.yml

MEDIUM-003 — CORS .env.production avec HTTP

Fichier : .env.production:40

MEDIUM-004 — MinIO bucket publicly readable

Fichier : docker-compose.yml:296mc anonymous set download veza/veza-files/public

MEDIUM-005 — Unbounded pagination (multiple handlers)

Fichiers : api/user/handler.go, core/admin/handler.go, et ~15 autres endpoints sans max(limit, 100)

MEDIUM-006 — File upload size validation missing (marketplace)

Fichier : handlers/marketplace.go:270-289 — pas de vérification file.Size

MEDIUM-007 — Nginx RTMP wildcard CORS

Fichier : infra/nginx-rtmp/nginx.conf:46Access-Control-Allow-Origin: *

MEDIUM-008 — Redis unprotected in development

Fichier : docker-compose.yml:35-56 — pas de --requirepass en dev

MEDIUM-009 — Nginx production missing HSTS header

Fichier : apps/web/nginx.production.conf:11-14

MEDIUM-010 — WebSocket message size not limited (playback)

Fichier : playback_websocket_handler.go:138-152 — pas de conn.SetReadLimit()

MEDIUM-011 — License download missing expiration check

Fichier : marketplace/service.go:806-840expires_at non vérifié

MEDIUM-012 — pprof profiling endpoint exposed

Fichier : cmd/api/main.go:8import _ "net/http/pprof" sans restriction d'accès


LOW FINDINGS

Fichier : config/config.go:138

LOW-002 — CASCADE DELETE extensif (30+ migrations)

Fichier : migrations/*.sql

LOW-003 — utils.HashPassword utilise bcrypt.DefaultCost

Fichier : utils/utils.go:57

LOW-004 — Staging validation workflow actions non épinglées

Fichier : staging-validation.yml:35

LOW-005 — Docker base images use :latest (dev Dockerfiles)

Fichiers : veza-backend-api/Dockerfile:28, veza-stream-server/Dockerfile:29

LOW-006 — JWT_SECRET hardcoded fallback in docker-compose

Fichier : docker-compose.yml:171dev-secret-key-minimum-32-characters-long


INFO FINDINGS

INFO-001 — Binary database dump dans le repo

Fichier : veza-backend-api/veza_back_api_db/

INFO-002 — hash_gen/create_test_user tools use bcrypt.DefaultCost

Fichiers : cmd/tools/hash_gen/main.go:11, cmd/tools/create_test_user/main.go:54,72

INFO-003 — No JWT key rotation mechanism

Fichier : services/jwt_service.go — pas de kid header, pas de support multi-clés


Contrôles Validés (PASS)

# Contrôle Statut Preuve
P01 Injection SQL PASS Toutes les requêtes utilisent des placeholders. ORDER BY protégé par whitelist.
P02 Injection de commande PASS ClamAV et FFmpeg via exec.CommandContext avec arguments séparés.
P03 JWT RS256 en production PASS RS256 primary, HS256 dev-only fallback. Algorithm validation empêche alg: none.
P04 Secrets non exposés PASS json:"-" sur passwords, tokens, secrets MFA, API keys hashées.
P05 crypto/rand (pas math/rand) PASS 19 fichiers utilisent crypto/rand.
P06 Webhook HMAC-SHA512 PASS hmac.Equal() timing-safe.
P07 Cookie HttpOnly PASS CookieHttpOnly: true.
P08 Cookie Secure auto-detect PASS getCookieSecure() retourne true en production.
P09 Track metrics hidden (backend) PASS PlayCount et LikeCount ont json:"-" sur le modèle Track.
P10 Rust memory safety PASS Aucun bloc unsafe.
P11 GDPR export PASS Endpoint fonctionnel, rate limité (3/24h).
P12 GDPR deletion flow PASS Anonymisation + hard delete 30j.
P13 Password validation PASS Complexité, historique 5 derniers, max 72 bytes.
P14 Account lockout PASS 5 attempts → 30min lockout, Redis + fallback in-memory.
P15 CSRF protection PASS 32-byte tokens, subtle.ConstantTimeCompare, Redis storage.
P16 Security headers (backend) PASS HSTS, CSP, X-Frame-Options, COEP/COOP.
P17 Container scanning PASS Trivy scans dans CI/CD.
P18 Secret scanning PASS Gitleaks action.
P19 OAuth PKCE PASS RFC 7636 implémenté (code_verifier + S256 challenge).
P20 OAuth state parameter PASS Généré avec crypto/rand, validé et consommé.
P21 OAuth redirect whitelist PASS URL validée contre whitelist configurée.
P22 Chat room membership PASS CanRead(), CanSend(), CanJoin() vérifient l'appartenance.
P23 Chat XSS protection PASS DOMPurify (frontend) + html.EscapeString (backend).
P24 Chat rate limiting PASS Redis sliding window, 10 msg/sec, fallback in-memory.

Méthodologie

Agents d'audit spécialisés

6 agents parallèles ont couvert les domaines suivants :

  1. Auth & JWT — JWT, bcrypt, sessions, cookies, OAuth, MFA, lockout
  2. API IDOR & Access Control — Authorization bypass, ownership checks, RBAC
  3. Input Validation & Injection — SQL, XSS, command, path traversal, file upload
  4. Infrastructure & Docker — Dockerfiles, docker-compose, CI/CD, secrets, CORS
  5. Business Logic & Payments — Payments, payouts, GDPR, subscriptions, marketplace
  6. WebSocket, Rust & Dependencies — WS security, memory safety, SCA

Scope couvert

Composant Fichiers analysés
Go backend ~200 fichiers .go
Rust stream server ~15 fichiers .rs
React frontend ~50 composants clés
CI/CD 11 workflows GitHub Actions
Docker 5 Dockerfiles, 5 docker-compose
Migrations 30+ fichiers SQL
Configuration .env.*, configs/, nginx

Rapport généré le 2026-03-13 — VEZA v0.12.6 Pentest Security Audit Auditeur : Claude Opus 4.6 + 6 agents spécialisés