Exemple de rapport

À quoi ressemble un rapport de Code Audit, du début à la fin.

Un rapport complet pour une application fictive, pour que vous en voyiez la structure et le niveau de détail avant d’en commander un. L’application est inventée. Les données de vulnérabilités proviennent d’une exécution réelle de composer audit.

Exemple pour une application fictive. Acme Logistics et Acme Fleet Portal n’existent pas.

Exemple de rapport, application fictive

« Acme Fleet Portal » et Acme Logistics n’existent pas. Le code, les métriques et les constats de configuration de ce rapport sont inventés pour montrer la structure et le niveau de détail d’un Code Audit Refberg. Les données de vulnérabilités sont réelles : le 24 octobre 2026, nous avons exécuté composer audit sur un fichier lock contenant les versions de paquets listées en section 4.1. Le nombre d’avis, les identifiants CVE et les versions corrigées proviennent de cette exécution. Les prix sont des exemples fondés sur nos prix de départ publics.

Rapport de Code Audit

ClientAcme Logistics Ltd (fictif)
ApplicationAcme Fleet Portal : réservations, facturation et API JSON pour l’application mobile des chauffeurs
Taille de l’auditM (de 50 000 à 200 000 lignes de code PHP)
Accèsdépôt en lecture seule, .env de préproduction et de production (expurgés), fichiers de configuration du serveur, crontab
Date24 octobre 2026
Rédigé parRefberg

1. Synthèse pour la direction

Le portail fonctionne et rapporte de l’argent, mais il repose sur des logiciels qui ont cessé de recevoir des correctifs de sécurité entre 2022 et 2025. Trois problèmes demandent une action cette semaine, avant tout travail de montée de version :

  1. Le serveur de préproduction peut être pris en main depuis Internet. Il est accessible publiquement, tourne en mode debug et contient un composant touché par une faille publiée d’exécution de code à distance (CVE-2021-3129). La préproduction contient une copie hebdomadaire de la base de production, avec les noms, adresses et factures des clients.
  2. Les mots de passe de production et la clé de chiffrement de l’application sont dans l’historique Git. Toute personne qui possède, ou a possédé, une copie du dépôt peut les lire. Ils n’ont pas été changés depuis 2021.
  3. Les sauvegardes sont stockées sur le même serveur que la base de données et n’ont jamais été restaurées. Une panne de disque ou un rançongiciel sur ce serveur emporterait les données et les sauvegardes en même temps.

Ces trois points peuvent être réglés en un à deux jours, sans modifier le code de l’application (section 6, étape 0).

Le problème de fond, c’est la plateforme elle-même : PHP 7.4 (fin de vie le 28 novembre 2022) et Laravel 6 (fin des correctifs de sécurité le 6 septembre 2022). L’analyse des dépendances a relevé 114 avis de sécurité publiés dans 20 paquets. Certains se corrigent avec des versions correctives au sein de Laravel 6. La plupart exigent la montée de version.

Il n’y a presque pas de tests automatisés (6,1 % de couverture de lignes, aucun sur les six parcours critiques pour l’activité) : aujourd’hui, toute modification se fait à l’aveugle. Nous recommandons l’option A : construire d’abord un filet de sécurité, puis monter de version en deux étapes au forfait jusqu’à Laravel 13 sous PHP 8.4, sur environ quatre mois, avec Care Standard à partir du 5e mois. L’option B (rester sur Laravel 6 avec un PHP corrigé) coûte moins cher cette année, et la section 6 explique dans quels cas elle se justifie.

2. Périmètre et méthode

Dans le périmètre : le code de l’application dans le dépôt (branche main au commit 4f1c9e2), composer.json et composer.lock, l’historique Git, les fichiers de configuration, la configuration serveur fournie par le client, le script de déploiement.

Outils : composer audit (Composer 2, base d’avis de sécurité de Packagist), PHPStan 2.x sans l’extension Laravel (Larastan pour Laravel 6 n’existe que pour l’ancienne branche PHPStan 0.12 ; nous relançons donc l’analyse avec Larastan après la montée de version du framework), Rector 2.x en mode dry-run, PHP_CodeSniffer avec PHPCompatibility, PHPUnit avec PCOV pour la couverture, gitleaks pour les secrets dans l’historique, git log pour la fréquence des modifications. Puis une revue manuelle des routes, de l’authentification, des envois de fichiers, de la génération de PDF, des files de messages et des tâches planifiées.

Hors périmètre : tests d’intrusion, tests de charge, revue de l’application mobile, systèmes du prestataire de paiement, configuration réseau de l’hébergeur. Nous n’avons tenté d’exploiter aucune faille. Quand nous disons qu’une vulnérabilité est exploitable, cela signifie que ses conditions préalables publiées sont réunies dans votre configuration.

3. Carte des risques

Probabilité et impact sont notés de 1 (faible) à 3 (élevé). Priorité : P0 cette semaine, P1 pendant la première étape, P2 pendant la montée de version.

IDRisqueProbabilitéImpactPriorité
R1Exécution de code à distance sur la préproduction publique via Ignition (CVE-2021-3129) ; la préproduction contient des données personnelles de production33P0
R2APP_KEY, mots de passe de la base et de la messagerie exposés dans l’historique Git depuis 202133P0
R3Sauvegardes sur le même serveur, jamais restaurées23P0
R4Génération de PDF avec ressources distantes activées sur dompdf 0.8.6 (CVE-2022-28368, injection de code à distance via les polices)23P0
R5Aucun test sur les parcours critiques ; 9 des 42 tests existants échouent32P1
R6PHP 7.4 d’Ubuntu 20.04 sans Ubuntu Pro : aucune mise à jour de sécurité de l’environnement d’exécution depuis mai 202523P1
R7Laravel 6 en fin de vie ; 5 avis sur le framework n’ont pas de correctif dans la branche 6.x22P2
R8Paquets abandonnés ou remplacés (SwiftMailer, Faker, Ignition 1.x)22P2
R9Un ancien développeur détenait toute la connaissance ; pas de runbook, déploiement par un script shell lancé à la main32P1

4.1 Dépendances

Résultat : 114 avis dans 20 paquets : 13 critiques, 44 élevés, 50 moyens, 7 faibles. 110 d’entre eux concernent des dépendances de production. Une sélection de paquets :

PaquetInstalléAvisAvis notablesPremière version corrigéeCorrigeable au sein de Laravel 6 ?
laravel/framework6.20.011CVE-2021-21263 (liaison des paramètres de requête), CVE-2021-43808 (XSS dans Blade), CVE-2024-52301 (environnement modifiable via la query string)6.20.45 pour 6 des 11en partie : 6.20.45
facade/ignition (dev)1.16.33CVE-2021-3129 (exécution de code à distance)1.16.14 (1.16.15 pour les trois)oui ; et il ne doit pas être installé en production
dompdf/dompdf0.8.614CVE-2022-28368 (injection de code à distance via les polices), CVE-2021-3838 (désérialisation)1.2.1 / 2.0.x / 3.1.6en partie : exige une montée de version majeure de laravel-dompdf
guzzlehttp/guzzle6.5.514CVE-2022-31090, CVE-2022-31091 (identifiants conservés après une redirection vers une autre origine)6.5.8 pour 5 des 14en partie
firebase/php-jwt5.2.02CVE-2021-46743 (confusion clé/algorithme)6.0.0oui, avec des modifications de code (nouvelle API)
league/flysystem1.0.702CVE-2021-32708 (situation de concurrence lors de l’écriture de fichiers)1.1.4oui
phpoffice/phpspreadsheet1.15.029XXE dans le lecteur XLSX (CVE-2024-45293, CVE-2024-48917)1.29.4 et suivantes (pour les deux failles XXE)probablement, via une version plus récente de maatwebsite/excel 3.1.x ; à confirmer à l’étape 1
swiftmailer/swiftmailer6.2.31CVE-2024-28859 (gadget de désérialisation)6.2.5oui, mais le paquet est abandonné

Abandonnés ou remplacés : swiftmailer/swiftmailer est marqué comme abandonné sur Packagist au profit de symfony/mailer (adopté par Laravel 9). fzaninotto/faker est marqué comme abandonné. facade/ignition a été remplacé par spatie/laravel-ignition ; sa dernière version date de janvier 2023. fideloper/proxy n’a connu aucune version depuis février 2022 ; ses fonctionnalités ont été intégrées à Laravel 9.

Pourquoi c’est plus important que le décompte : les éléments dangereux sont ceux dont votre configuration remplit les conditions préalables. Dans cette application, il s’agit d’Ignition en préproduction (R1, le mode debug est activé), de dompdf avec enable_remote => true dans config/dompdf.php (R4, le modèle de facture charge le logo par URL), et de php-jwt dans l’API mobile (nous n’avons pas pu confirmer l’exploitabilité sans connaître la configuration des clés ; voir 4.4).

4.2 Tests et CI

  • 42 tests PHPUnit, dont 9 échouent sur main. Les échecs datent de 2023, et les tests n’ont plus été exécutés depuis.
  • Couverture de lignes : 6,1 %. Sont couverts : deux classes utilitaires et le formulaire de connexion.
  • Parcours critiques sans aucun test : création de réservation, calcul du prix, génération des factures (PDF), callback de paiement, authentification de l’API chauffeurs, export mensuel des factures (XLSX).
  • Aucun pipeline de CI. deploy.sh lance git pull, composer install (sans --no-dev, d’où la présence d’Ignition et de Faker sur les serveurs) et php artisan migrate --force en production, dans cet ordre, sans étape de sauvegarde.

4.3 Analyse statique et préparation à la montée de version

ContrôleRésultat
PHPStan niveau 0 (sans extension Laravel)286 erreurs. 41 sont des appels à des méthodes ou fonctions non définies, dont au moins 7 sur des chemins de code accessibles depuis les routes
PHPStan niveau 5 (sans extension Laravel)1 912 erreurs. Nous recommandons une baseline au niveau 5, et aucune nouvelle erreur à partir de l’étape 1
PHPCompatibility, cible PHP 8.437 erreurs, 112 avertissements
Rector en dry-run, jeu de règles PHP 8.1214 fichiers seraient modifiés ; environ 80 % des changements sont mécaniques (promotion des propriétés du constructeur, str_contains, opérateur nullsafe)

Points bloquants pour PHP 8, dans l’ordre où ils apparaîtraient :

  1. app/Libraries/LegacyCsv.php utilise each(), supprimée en PHP 8.0. Cette classe sert à l’import mensuel : erreur fatale dès la première exécution après la montée de version.
  2. 23 classes utilisent des propriétés dynamiques (dépréciées en PHP 8.2), surtout dans app/Services/Pricing/.
  3. Interpolation de chaînes ${…} (signe dollar hors des accolades) à 31 endroits (dépréciée en PHP 8.2).
  4. Paramètres implicitement nullables dans 58 signatures de méthodes (dépréciés en PHP 8.4).
  5. Laravel 6 est pris en charge au plus sur PHP 8.0 : les montées de version de PHP et du framework doivent donc être imbriquées (section 6).

Points chauds

Les fichiers les plus souvent modifiés au cours des 24 derniers mois, avec leur taille.

FichierLignesCommits (24 mois)Remarque
app/Http/Controllers/BookingController.php2 14061tarification, validation et e-mails dans une seule classe ; premier candidat pour les tests de caractérisation
app/Services/InvoiceService.php1 31038génération des PDF, numérotation, TVA ; la numérotation utilise MAX(id)+1 sans verrou
app/Http/Controllers/Api/DriverController.php87029gestion des JWT écrite à la main autour de php-jwt

4.4 Configuration et sécurité

IDConstatPreuveRecommandation
C1La préproduction est publique, APP_DEBUG=true, Ignition installéstaging.acme-fleet.example répond sans authentificationrestreindre par IP ou par authentification HTTP dès aujourd’hui ; passer APP_DEBUG=false ; déployer avec --no-dev
C2La base de préproduction est une copie hebdomadaire de la production, avec des données personnellestâche cron refresh-staging.shremplacer par une copie anonymisée ; c’est aussi un problème RGPD
C3Secrets dans l’historiquegitleaks : .env.production versionné en mars 2021 puis supprimé dans un commit ultérieur ; contient APP_KEY, DB_PASSWORD, MAIL_PASSWORDrenouveler les trois ; voir la remarque sur APP_KEY ci-dessous
C4Proxies de confiance réglés sur *app/Http/Middleware/TrustProxies.phpindiquer l’adresse du répartiteur de charge ; aujourd’hui, n’importe quel client peut définir sa propre IP via X-Forwarded-For, ce qui neutralise la limitation des tentatives de connexion
C5Cookie de session sans attribut Secure, pas de HSTSSESSION_SECURE_COOKIE non défini ; pas d’en-tête Strict-Transport-Securityactiver les deux après avoir vérifié que tout passe en HTTPS
C6Ressources distantes de dompdf activéesconfig/dompdf.php : enable_remote => trueintégrer le logo comme fichier local et désactiver les ressources distantes
C7Worker de file lancé par cron toutes les minutes, en rootcrontab -l de rootle faire tourner sous Supervisor ou systemd, avec l’utilisateur de l’application
C8Sauvegardes : mysqldump chaque nuit vers /var/backups sur le même serveurcrontab, contenu du disquecopie hors site, chiffrement, test de restauration mensuel
C9La vérification des JWT accepte l’algorithme indiqué dans l’en-tête du jetonDriverController::decodeToken()traité par la montée de version vers php-jwt 6 ; corriger le gestionnaire en même temps

À propos du renouvellement d’APP_KEY

Laravel utilise cette clé pour les cookies chiffrés, les URL signées et toute valeur que votre code chiffre avec Crypt::encrypt() ou encrypt(). La changer déconnecte tous les utilisateurs et rend ces valeurs illisibles si elles ne sont pas chiffrées à nouveau. Le portail stocke un champ de ce type (les numéros d’identité nationaux des chauffeurs, chiffrés dans un mutator du modèle). L’étape 0 comprend un court script qui déchiffre avec l’ancienne clé et rechiffre avec la nouvelle.

4.5 Environnement d’exécution

Le serveur de production tourne sous Ubuntu 20.04 avec le paquet PHP 7.4 de la distribution. La maintenance de sécurité standard d’Ubuntu 20.04 a pris fin en mai 2025. Le serveur n’est pas rattaché à Ubuntu Pro : le paquet PHP et le reste du système d’exploitation ne reçoivent donc plus aucune mise à jour de sécurité.

Rattacher le serveur à Ubuntu Pro rétablirait ces mises à jour jusqu’en mai 2030 pour les paquets du dépôt main d’Ubuntu, dont fait partie PHP 7.4. Cela ne corrige que l’environnement d’exécution, et ne change rien pour Laravel ni pour les paquets de la section 4.1.

4.6 Ce qui est en bon état

  • Les migrations reconstruisent le schéma complet à partir d’une base vide, sans erreur : un environnement reproductible ne demande aucun SQL manuel.
  • Le callback de paiement vérifie la signature du prestataire avant de modifier une commande.
  • L’application utilise les files, le planificateur et les composants mail de Laravel, sans remplacements maison : la montée de version peut suivre les guides officiels.

5. Priorités

PrioritéQuoiPourquoi en premier
P0, cette semaineC1, C2, C3, C6, C8exploitable dès maintenant, ou rendrait un incident irrécupérable
P0, cette semainelaravel/framework 6.20.0 → 6.20.45, league/flysystem → 1.1.4, guzzlehttp/guzzle → 6.5.8, guzzlehttp/psr7 → 1.9.1versions correctives, même version majeure, risque faible même sans tests
P1, étape 1tests sur les six parcours critiques, CI, runbook, supervision, C4, C5, C7, Ubuntu Pro ou un nouveau serveurrien d’autre ne peut être modifié sans risque tant que ce socle n’existe pas
P2, étapes 2 et 3montée de version de PHP et de Laravel, remplacement des paquets abandonnés, C9exige le filet de tests de l’étape 1

6. Plan et prix fermes

Les prix de cet exemple sont fondés sur nos prix de départ publics. Un vrai audit se termine par un devis comme celui-ci, avec des prix fermes pour le périmètre qui y est décrit.

Option A (recommandée) : filet de sécurité, puis Laravel 13 sous PHP 8.4

Étapes 1 à 3 au total : un Takeover M et deux étapes de montée de version M, environ quatre mois. État final : Laravel 13 (correctifs de sécurité jusqu’au 17 mars 2028) sous PHP 8.4 (support de sécurité jusqu’au 31 décembre 2028), des tests sur chaque parcours critique, une CI sur chaque modification et un runbook utilisable par un autre développeur.
ÉtapePérimètreDuréePrix fermePaiement
0. Contenirles points classés P0 en section 5 ; votre équipe peut s’en charger en 1 à 2 jours en suivant nos instructions pas à pas, ou nous le faisons pendant la première semaine de l’étape 11 semaineinclus dans l’étape 1avec l’étape 1
1. Takeoverenvironnement Docker qui reproduit la production ; CI ; tests de caractérisation pour les six parcours critiques ; baseline PHPStan au niveau 5 ; sauvegardes hors site avec test de restauration ; supervision ; runbook et cartographie de l’architecture ; inventaire des accès4 semaines (taille M)3 000 €100 % à la commande
2. Montée de version ILaravel 6 → 9 et PHP 7.4 → 8.1 par paliers (6 → 8 sous PHP 7.4, puis PHP 8.0, puis Laravel 9 sous PHP 8.1) ; SwiftMailer → Symfony Mailer ; php-jwt 6 avec la correction du gestionnaire JWT ; dompdf 2.x ; Guzzle 7 ; Faker → fakerphp/faker ; réécriture de LegacyCsv6 semaines6 000 €30 % / 70 % après une CI au vert et votre validation en préproduction
3. Montée de version IILaravel 9 → 13 et PHP 8.1 → 8.4 ; serveur Ubuntu 24.04 ; phpspreadsheet et dompdf dans leurs versions actuelles ; suppression de fideloper/proxy ; propriétés dynamiques et dépréciations traitées6 semaines6 000 €30 % / 70 % après une CI au vert et votre validation en préproduction
Care Standardmises à jour mensuelles de PHP et des dépendances, supervision, 8 heures d’intervention, prise en charge des incidents critiques sous 4 heures ouvrées, revue trimestrielleà partir du 5e mois800 €/moismensuel

Option B : maintenir en sécurité sur la version actuelle pendant 12 mois

Étapes 0 et 1 comme ci-dessus (3 000 €), Ubuntu Pro sur le serveur existant pour les correctifs de l’environnement d’exécution (abonnement payé par vous à Canonical), les versions correctives de la section 5, et Care Basic à 400 € par mois.

Cette option garde les failles évidentes fermées pendant que vous décidez de l’avenir de l’application. Elle ne supprime ni les 5 avis Laravel sans correctif dans la branche 6.x, ni les problèmes de dompdf et de phpspreadsheet qui exigent des montées de version majeures, ni les points bloquants pour PHP 8. Dans 12 mois, l’option A coûtera à peu près la même chose qu’aujourd’hui, plus les nouveaux avis publiés entre-temps.

L’option B se justifie si le portail doit être remplacé ou retiré d’ici 18 mois, ou si le budget de l’année est figé.

Option C : réécriture

Nous ne la recommandons pas. Les règles métier du portail (tarification, numérotation des factures, gestion de la TVA) n’existent que dans le code, et aucune n’est testée. Une réécriture devrait les redécouvrir, et l’ancien système aurait quand même besoin de l’option B pendant la construction du nouveau.

7. Ce dont nous avons besoin pour démarrer

  1. Une décision entre l’option A et l’option B.
  2. Pour l’étape 0 : une personne disposant d’un accès administrateur à la préproduction et à la base de données, qui peut renouveler les mots de passe avec nous, en visio ou par e-mail.
  3. Pour l’étape 1 : des comptes nominatifs pour nous sur l’hébergement Git et en préproduction, et une personne capable de dire ce que doivent faire les six parcours critiques quand le code et les utilisateurs ne sont pas d’accord.

Annexe A : analyse complète des dépendances. La sortie complète de composer audit (JSON, les 114 avis) est livrée avec le rapport dans un fichier séparé.

Le rapport et tous les constats sont confidentiels et couverts par l’accord de confidentialité.

Comment un rapport aussi détaillé tient dans ce prix

Les outils comptent, et nous lisons le code. Les outils de programmation IA, utilisés avec votre accord écrit, accélèrent la lecture et les vérifications ; un ingénieur relit chaque constat avant qu’il n’entre dans le rapport. Plus de détails dans Notre méthode et sur la page Sécurité et confiance.

Vous voulez un rapport de ce type pour votre application ?

Code Audit à partir de 800 €, rapport sous 5 à 7 jours ouvrés. Vous hésitez encore ? Commencez par un Debt Check à 300 €.