- 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>
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_countetfollowing_countdePublicUserResponse - Supprimer
followers_countdeSuggestionUser - 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@v2docker/setup-buildx-action@v3(2 usages)aquasecurity/trivy-action@0.28.0et@master(5 usages)sigstore/cosign-installer@v3actions-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é.
LOW-001 — Cookie SameSite=Lax au lieu de Strict
| 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