veza/docs/PENTEST_REPORT_VEZA_v0.12.6.md
senke 7e05cdf5da feat(v0.12.6): pentest security audit — 3 deliverables
- PENTEST_REPORT_VEZA_v0.12.6.md: 14 findings (0 CRIT, 2 HIGH, 5 MEDIUM, 4 LOW, 3 INFO), 18 PASS controls
- REMEDIATION_MATRIX_v0.12.6.md: prioritized remediation actions (P1: 4h, P2: 5h, P3: 5.5h)
- ASVS_CHECKLIST_v0.12.6.md: OWASP ASVS Level 2 — 92/101 (91.1%) conformity

Methodology: SAST + manual code review, OWASP Top 10 2021, API Security Top 10 2023

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

14 KiB

Rapport de Pentest — VEZA v0.12.6

Date : 2026-03-13 Auditeur : Claude Code (SAST + revue manuelle de code) 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 0
HIGH 2
MEDIUM 5
LOW 4
INFO 3
Total findings 14
PASS (contrôles validés) 18

Posture globale : La codebase VEZA présente une posture de sécurité solide pour une RC. Aucune vulnérabilité critique n'a été identifiée. Les 2 findings HIGH concernent des fuites de métriques de popularité dans l'API publique (violation éthique) et un contournement potentiel de rate limiting via IP spoofing. Les contrôles cryptographiques, l'authentification JWT, la prévention d'injection SQL et la conformité RGPD sont bien implémentés.


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 veza-backend-api/internal/handlers/common.go:601-610
CVSS 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Description : La méthode GetClientIP() lit directement le header X-Forwarded-For sans passer par c.ClientIP() de Gin, qui respecte Engine.SetTrustedProxies. Un attaquant peut injecter un faux header X-Forwarded-For pour contourner les rate limits basés sur l'IP.

// VULNÉRABLE (common.go:604)
if ip := c.GetHeader("X-Forwarded-For"); ip != "" {
    return strings.Split(ip, ",")[0]
}

Impact : Contournement complet du rate limiting pour les endpoints non authentifiés (login, register, password reset). Permet des attaques brute-force sur les credentials.

Remédiation : Remplacer par c.ClientIP() et configurer gin.Engine.SetTrustedProxies() avec les IPs des reverse proxies de confiance.

Note : Le middleware metrics_protection.go:51-53 utilise correctement c.ClientIP() — le fix est déjà documenté dans un commentaire SECURITY(MEDIUM-002).


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

Champ Valeur
Sévérité HIGH
OWASP Business Logic Flaw
Fichiers user_service.go:75, social_service.go:321, types/stats.go:31
Réf. ORIGIN ORIGIN_UI_UX_SYSTEM.md §13.4, §14.2

Description : Les endpoints publics de profil utilisateur (GET /api/v1/users/:id, GET /api/v1/users/by-username/:username) retournent followers_count et following_count dans la réponse JSON via PublicUserResponse. L'endpoint GET /api/v1/users/suggestions retourne aussi followers_count via SuggestionUser.

Ceci viole le principe éthique fondamental de VEZA : les métriques de popularité ne doivent JAMAIS être exposées publiquement.

Impact : Permet le classement social des utilisateurs, contredit les engagements éthiques de la plateforme (privacy policy §4, ORIGIN §13.4).

Remédiation :

  • Supprimer followers_count et following_count de PublicUserResponse
  • Supprimer followers_count de SuggestionUser
  • Exposer ces métriques uniquement dans le dashboard créateur privé (derrière auth + ownership check)

MEDIUM-001 — Incohérence du coût bcrypt

Champ Valeur
Sévérité MEDIUM
OWASP A02:2021 — Cryptographic Failures
Fichier veza-backend-api/internal/core/auth/service.go:156, :986

Description : Le service d'authentification utilise bcrypt.DefaultCost (10) pour le hachage des mots de passe lors de l'inscription et du reset, tandis que password_service.go utilise correctement bcryptCost = 12.

// auth/service.go:156 — coût 10
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)

// password_service.go:22 — coût 12
const bcryptCost = 12

Impact : Les mots de passe créés via Register() ou ResetPasswordWithToken() sont 4x plus rapides à brute-forcer que ceux créés via PasswordService.ChangePassword().

Remédiation : Remplacer bcrypt.DefaultCost par la constante bcryptCost (12) dans auth/service.go, ou centraliser le hachage dans PasswordService.


MEDIUM-002 — GitHub Actions non épinglées par SHA

Champ Valeur
Sévérité MEDIUM
OWASP A08:2021 — Software and Data Integrity Failures
Fichiers sast.yml, security-scan.yml, cd.yml, stream-ci.yml, container-scan.yml, staging-validation.yml

Description : 12+ actions GitHub sont référencées par tag (@v3, @v2, @master) au lieu de SHA complet. Un compromission du repo upstream permettrait l'injection de code malveillant dans le pipeline CI/CD.

Actions concernées :

  • github/codeql-action/*@v3 (3 usages)
  • gitleaks/gitleaks-action@v2
  • docker/setup-buildx-action@v3 (2 usages)
  • aquasecurity/trivy-action@0.28.0 et @master (5 usages)
  • sigstore/cosign-installer@v3
  • actions-rust-lang/audit@v1

Impact : Supply chain attack sur le pipeline CI/CD. Exfiltration de secrets, injection de code dans les builds.

Remédiation : Épingler toutes les actions par SHA (déjà fait pour actions/checkout, actions/setup-go, etc.). Utiliser Dependabot pour les mises à jour.


MEDIUM-003 — CORS .env.production avec HTTP

Champ Valeur
Sévérité MEDIUM
OWASP A05:2021 — Security Misconfiguration
Fichier veza-backend-api/.env.production:40

Description : Le fichier .env.production contient des origines CORS en HTTP avec port 5173 (dev) :

CORS_ALLOWED_ORIGINS=http://veza.com:5173,http://veza.talas.fr:5173,...

Bien qu'un commentaire indique les valeurs HTTPS pour la production, le fichier pourrait être déployé tel quel.

Impact : En cas de déploiement accidentel, les cookies auth pourraient être envoyés sur des connexions HTTP non chiffrées.

Remédiation : Renommer en .env.development ou mettre les valeurs HTTPS par défaut avec override via variables d'environnement.


MEDIUM-004 — Social Post like_count exposé publiquement

Champ Valeur
Sévérité MEDIUM
OWASP Business Logic Flaw
Fichier veza-backend-api/internal/core/social/models.go:32

Description : Le modèle Post (social) expose like_count avec json:"like_count" sans tag json:"-". Les posts sociaux sérialisés dans les réponses API incluent le nombre de likes.

Contrairement au modèle Track qui a correctement json:"-" sur PlayCount et LikeCount, les posts sociaux n'ont pas cette protection.

Impact : Incohérence avec la politique éthique de non-exposition des métriques de popularité.

Remédiation : Ajouter json:"-" au champ LikeCount du modèle Post, ou le rendre visible uniquement à l'auteur du post.


MEDIUM-005 — Dashboard TrackPreview expose play_count/like_count sans ownership check granulaire

Champ Valeur
Sévérité MEDIUM
OWASP API1:2023 — Broken Object Level Authorization
Fichier veza-backend-api/internal/handlers/dashboard.go:149-150

Description : La struct TrackPreview expose play_count et like_count en JSON. L'endpoint dashboard (GET /api/v1/dashboard) est protégé par auth et retourne les tracks du user authentifié — donc c'est le créateur qui voit ses propres métriques. Cependant, si la struct TrackPreview est réutilisée ailleurs, les métriques fuiteraient.

Impact : Risque faible actuellement (endpoint bien protégé), mais architecture fragile.

Remédiation : Créer un type TrackPreviewPublic sans métriques pour les contextes publics, garder TrackPreview avec métriques uniquement pour le dashboard privé.


Champ Valeur
Sévérité LOW
Fichier veza-backend-api/internal/config/config.go:138

Description : Les cookies d'authentification utilisent SameSite=Lax au lieu de Strict. Cela permet l'envoi de cookies lors de navigations top-level depuis des sites tiers (par exemple, un lien depuis un email de phishing).

Impact : Risque CSRF résiduel pour les requêtes GET qui modifient l'état (normalement aucune dans une API REST bien conçue).

Remédiation : Passer à SameSite=Strict si aucun flow OAuth/redirect externe ne nécessite Lax.


LOW-002 — CASCADE DELETE extensif dans les migrations

Champ Valeur
Sévérité LOW
Fichier veza-backend-api/migrations/*.sql (30+ occurrences)

Description : La quasi-totalité des clés étrangères utilisent ON DELETE CASCADE. En cas de suppression accidentelle d'un utilisateur, toutes ses données associées (tracks, messages, playlists, orders, etc.) sont supprimées en cascade.

Impact : Perte de données irréversible en cas d'erreur admin ou de bug dans la logique de suppression.

Remédiation : Utiliser ON DELETE RESTRICT ou ON DELETE SET NULL pour les entités business critiques (orders, payments). Implémenter le soft delete systématiquement.


LOW-003 — utils.HashPassword utilise bcrypt.DefaultCost

Champ Valeur
Sévérité LOW
Fichier veza-backend-api/internal/utils/utils.go:57

Description : La fonction utilitaire HashPassword() utilise bcrypt.DefaultCost (10). Si elle est appelée en production (au lieu de PasswordService), le coût sera inférieur au standard de 12.

Remédiation : Aligner sur bcryptCost = 12 ou supprimer cette fonction si elle n'est pas utilisée en production.


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

Champ Valeur
Sévérité LOW
Fichier .github/workflows/staging-validation.yml:35

Description : docker/setup-buildx-action@v3 non épinglé par SHA dans le workflow de staging.

Remédiation : Épingler par SHA comme les autres actions.


INFO-001 — Binary database dump dans le repo

Champ Valeur
Sévérité INFO
Fichier veza-backend-api/veza_back_api_db/

Description : Un dump de base de données binaire est présent dans le repo. Bien que les données semblent être de développement, des informations sensibles (hashes, tokens) peuvent s'y trouver.

Remédiation : Ajouter ce répertoire au .gitignore et supprimer de l'historique git avec git filter-branch ou BFG Repo-Cleaner.


INFO-002 — hash_gen tool utilise bcrypt.DefaultCost

Champ Valeur
Sévérité INFO
Fichier veza-backend-api/cmd/tools/hash_gen/main.go:11

Description : L'outil CLI hash_gen utilise bcrypt.DefaultCost. Comme c'est un outil de développement, l'impact est nul, mais il serait bon d'aligner pour la cohérence.


INFO-003 — create_test_user tool utilise bcrypt.DefaultCost

Champ Valeur
Sévérité INFO
Fichier veza-backend-api/cmd/tools/create_test_user/main.go:54,72

Description : Même constat que INFO-002 pour l'outil de création d'utilisateurs test.


Contrôles Validés (PASS)

# Contrôle Statut Preuve
P01 Injection SQL PASS Toutes les requêtes db.Raw() utilisent des placeholders ?. Aucune concaténation de chaînes dans les requêtes SQL.
P02 Injection de commande PASS Aucun usage de exec.Command, os/exec, ou équivalent avec input utilisateur.
P03 JWT RS256 en production PASS jwt_service.go : RS256 primary, HS256 fallback dev only.
P04 Secrets non exposés PASS PasswordHash, tokens, secrets MFA ont json:"-". API keys hashées.
P05 crypto/rand (pas math/rand) PASS 19 fichiers utilisent crypto/rand. Aucun usage de math/rand pour la sécurité.
P06 Webhook HMAC-SHA512 PASS Vérification HMAC correcte avec hmac.Equal() (timing-safe).
P07 Race condition prevention PASS SELECT FOR UPDATE utilisé pour les opérations concurrentes sur les soldes.
P08 Cookie HttpOnly PASS CookieHttpOnly: true pour access_token et refresh_token.
P09 Cookie Secure auto-detect PASS getCookieSecure() retourne true en production automatiquement.
P10 Track metrics hidden (backend) PASS track.go:42-43 : PlayCount et LikeCount ont json:"-".
P11 Rust safety PASS Aucun bloc unsafe dans veza-stream-server/src/.
P12 GDPR export PASS gdpr_export_handler.go + tests E2E.
P13 GDPR deletion PASS account_deletion_handler.go : anonymisation + hard delete 30j.
P14 Password validation PASS Longueur min, complexité, historique des 5 derniers, max 72 bytes (bcrypt limit).
P15 Rate limiting PASS Middleware rate limit configuré sur les endpoints sensibles.
P16 Security headers PASS HSTS, CSP, X-Frame-Options, COEP/COOP configurés.
P17 Container scanning PASS Trivy scans dans CI/CD (cd.yml, container-scan.yml).
P18 Secret scanning PASS Gitleaks action dans security-scan.yml.

Méthodologie

Outils et techniques

  • SAST : Analyse statique manuelle du code source (Go, Rust, TypeScript)
  • Pattern matching : Recherche de patterns vulnérables (SQL concat, exec.Command, math/rand, unsafe, etc.)
  • Configuration review : Analyse des fichiers .env, Docker, CI/CD, CORS
  • Architecture review : Vérification de l'isolation des services, des contrôles d'accès, du flux de données
  • Dependency analysis : Revue des actions GitHub, crates Rust, packages npm
  • ORIGIN compliance : Vérification de la conformité avec les spécifications ORIGIN (éthique, sécurité, business logic)

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 3 Dockerfiles, 3 docker-compose
Migrations 30+ fichiers SQL
Configuration .env.*, configs/

Rapport généré le 2026-03-13 — VEZA v0.12.6 Pentest Security Audit