Beispielbericht

So sieht ein Bericht aus dem Code Audit aus, von der ersten bis zur letzten Seite.

Ein vollständiger Beispielbericht für eine fiktive Anwendung. So sehen Sie Aufbau und Tiefe, bevor Sie ein Audit beauftragen. Die Anwendung ist erfunden, die Daten zu Sicherheitslücken stammen aus einem echten Lauf von composer audit.

Beispiel für eine fiktive Anwendung. Acme Logistics und Acme Fleet Portal gibt es nicht.

Beispielbericht, fiktive Anwendung

„Acme Fleet Portal“ und Acme Logistics gibt es nicht. Code, Kennzahlen und Konfigurationsbefunde in diesem Bericht sind erfunden. Sie zeigen Aufbau und Tiefe eines Code Audits von Refberg. Die Daten zu Sicherheitslücken sind echt: Am 24. Oktober 2026 haben wir composer audit gegen eine Lock-Datei mit den Paketversionen aus Abschnitt 4.1 laufen lassen. Anzahl der Advisories, CVE-Kennungen und behobene Versionen stammen aus diesem Lauf. Die Preise sind Beispiele auf Basis unserer veröffentlichten Einstiegspreise.

Code-Audit-Bericht

KundeAcme Logistics Ltd (fiktiv)
AnwendungAcme Fleet Portal: Buchungen, Rechnungsstellung und eine JSON-API für die mobile Fahrer-App
Audit-GrößeM (50.000 bis 200.000 Zeilen PHP-Code)
ZugriffLesezugriff auf das Repository, .env von Staging und Produktion (geschwärzt), Konfigurationsdateien des Servers, crontab
Datum24. Oktober 2026
Erstellt vonRefberg

1. Zusammenfassung für die Geschäftsführung

Das Portal läuft und bringt Umsatz, aber es baut auf Software, die zwischen 2022 und 2025 die letzten Sicherheitsupdates bekommen hat. Drei Probleme müssen noch diese Woche gelöst werden, vor jeder Upgrade-Arbeit:

  1. Der Staging-Server lässt sich aus dem Internet übernehmen. Er ist öffentlich erreichbar, läuft im Debug-Modus und enthält eine Komponente mit einer veröffentlichten Lücke zur Ausführung von Schadcode aus der Ferne (CVE-2021-3129). Auf Staging liegt eine wöchentliche Kopie der Produktionsdatenbank, mit Namen, Adressen und Rechnungen von Kunden.
  2. Produktionspasswörter und der Verschlüsselungsschlüssel der Anwendung stehen in der Git-Historie. Jeder, der eine Kopie des Repositorys hat oder einmal hatte, kann sie lesen. Sie wurden seit 2021 nicht geändert.
  3. Die Backups liegen auf demselben Server wie die Datenbank und wurden nie zurückgespielt. Ein Plattendefekt oder Ransomware auf diesem Server würde Daten und Backups gemeinsam vernichten.

Alle drei lassen sich in ein bis zwei Tagen schließen, ohne den Anwendungscode zu ändern (Abschnitt 6, Etappe 0).

Das größere Problem auf längere Sicht ist die Plattform selbst: PHP 7.4 (Supportende 28. November 2022) und Laravel 6 (Sicherheitsupdates beendet 6. September 2022). Der Abhängigkeitsscan hat 114 veröffentlichte Security Advisories in 20 Paketen gefunden. Einige lassen sich mit Patch-Releases innerhalb von Laravel 6 beheben, die meisten erst mit dem Upgrade.

Automatisierte Tests gibt es kaum (6,1 % Zeilenabdeckung, keine für die sechs geschäftskritischen Pfade), jede Änderung ist heute also ein Ratespiel. Wir empfehlen Option A: zuerst ein Sicherheitsnetz, dann ein Upgrade in zwei Etappen zum Festpreis auf Laravel 13 mit PHP 8.4, in rund vier Monaten, ab Monat 5 mit Care Standard. Option B (auf Laravel 6 bleiben, mit gepatchtem PHP) kostet dieses Jahr weniger. Wann sie sinnvoll ist, steht in Abschnitt 6.

2. Umfang und Vorgehen

Im Umfang: Anwendungscode im Repository (Branch main, Commit 4f1c9e2), composer.json und composer.lock, Git-Historie, Konfigurationsdateien, vom Kunden bereitgestellte Serverkonfiguration, Deploy-Skript.

Werkzeuge: composer audit (Composer 2, Advisory-Datenbank von Packagist), PHPStan 2.x ohne Laravel-Erweiterung (Larastan für Laravel 6 gibt es nur für die alte PHPStan-Linie 0.12, deshalb wiederholen wir die Analyse mit Larastan nach dem Framework-Upgrade), Rector 2.x im Probelauf (Dry Run), PHP_CodeSniffer mit PHPCompatibility, PHPUnit mit PCOV für die Testabdeckung, gitleaks für Secrets in der Historie, git log für die Änderungshäufigkeit. Danach eine manuelle Prüfung von Routen, Authentifizierung, Datei-Uploads, PDF-Erzeugung, Queues und Cronjobs.

Nicht im Umfang: Penetrationstests, Lasttests, Prüfung der mobilen App, die Systeme des Zahlungsanbieters und das Netzwerk-Setup des Hosters. Wir haben nichts davon aktiv ausgenutzt. Wenn wir eine Lücke als ausnutzbar bezeichnen, heißt das: Die veröffentlichten Voraussetzungen sind in Ihrer Konfiguration erfüllt.

3. Risikoübersicht

Eintrittswahrscheinlichkeit und Auswirkung von 1 (gering) bis 3 (hoch). Priorität: P0 diese Woche, P1 in der ersten Etappe, P2 während des Upgrades.

IDRisikoWahrscheinlichkeitAuswirkungPriorität
R1Ausführung von Schadcode aus der Ferne auf dem öffentlichen Staging über Ignition (CVE-2021-3129); auf Staging liegen personenbezogene Daten aus der Produktion33P0
R2APP_KEY, Datenbank- und Mail-Passwörter seit 2021 in der Git-Historie einsehbar33P0
R3Backups auf demselben Server, nie zurückgespielt23P0
R4PDF-Erzeugung mit aktivierten Remote-Ressourcen in dompdf 0.8.6 (CVE-2022-28368, Einschleusen von Code über Schriftarten)23P0
R5Keine Tests für die kritischen Pfade; 9 von 42 vorhandenen Tests schlagen fehl32P1
R6PHP 7.4 aus Ubuntu 20.04 ohne Ubuntu Pro: seit Mai 2025 keine Sicherheitsupdates für die Laufzeitumgebung23P1
R7Laravel 6 hat sein Supportende überschritten; für 5 Framework-Advisories gibt es auf der 6.x-Linie keinen Fix22P2
R8Nicht mehr gepflegte oder abgelöste Pakete (SwiftMailer, Faker, Ignition 1.x)22P2
R9Das gesamte Wissen lag bei einem ehemaligen Entwickler; kein Runbook, das Deployment ist ein Shell-Skript, das von Hand gestartet wird32P1

4.1 Abhängigkeiten

Ergebnis: 114 Advisories in 20 Paketen: 13 kritisch, 44 hoch, 50 mittel, 7 niedrig. 110 davon betreffen Produktionsabhängigkeiten. Eine Auswahl:

PaketInstalliertAdvisoriesWichtige AdvisoriesErste behobene VersionInnerhalb von Laravel 6 behebbar?
laravel/framework6.20.011CVE-2021-21263 (Query Binding), CVE-2021-43808 (Blade-XSS), CVE-2024-52301 (Umgebung über Query-String)6.20.45 für 6 von 11teilweise: 6.20.45
facade/ignition (dev)1.16.33CVE-2021-3129 (Ausführung von Schadcode aus der Ferne)1.16.14 (1.16.15 für alle drei)ja; darf außerdem nicht in Produktion installiert sein
dompdf/dompdf0.8.614CVE-2022-28368 (Einschleusen von Code über Schriftarten), CVE-2021-3838 (Deserialisierung)1.2.1 / 2.0.x / 3.1.6teilweise: erfordert ein Major-Upgrade von laravel-dompdf
guzzlehttp/guzzle6.5.514CVE-2022-31090, CVE-2022-31091 (Zugangsdaten bleiben nach Weiterleitung auf einen anderen Origin erhalten)6.5.8 für 5 von 14teilweise
firebase/php-jwt5.2.02CVE-2021-46743 (Verwechslung von Schlüssel und Algorithmus)6.0.0ja, mit Codeänderungen (neue API)
league/flysystem1.0.702CVE-2021-32708 (Race Condition beim Schreiben von Dateien)1.1.4ja
phpoffice/phpspreadsheet1.15.029XXE im XLSX-Reader (CVE-2024-45293, CVE-2024-48917)1.29.4 und neuer (für die beiden XXE-Lücken)wahrscheinlich, über ein neueres maatwebsite/excel 3.1.x; in Etappe 1 zu bestätigen
swiftmailer/swiftmailer6.2.31CVE-2024-28859 (Deserialisierungs-Gadget)6.2.5ja, aber das Paket wird nicht mehr gepflegt

Nicht mehr gepflegt oder abgelöst: swiftmailer/swiftmailer ist auf Packagist als aufgegeben markiert, Nachfolger ist symfony/mailer (Laravel 9 ist darauf umgestiegen). fzaninotto/faker ist als aufgegeben markiert. facade/ignition wurde durch spatie/laravel-ignition abgelöst; das letzte Release erschien im Januar 2023. fideloper/proxy hat seit Februar 2022 kein Release mehr bekommen; die Funktion ist in Laravel 9 aufgegangen.

Warum das wichtiger ist als die Zahl: Gefährlich sind die Lücken, deren Voraussetzungen bei Ihnen erfüllt sind. In dieser Anwendung sind das Ignition auf Staging (R1, der Debug-Modus ist an), dompdf mit enable_remote => true in config/dompdf.php (R4, die Rechnungsvorlage lädt das Logo per URL) und php-jwt in der mobilen API (ohne Einblick in die Schlüsselkonfiguration konnten wir die Ausnutzbarkeit nicht bestätigen; siehe 4.4).

4.2 Tests und CI

  • 42 PHPUnit-Tests, davon 9 rot auf main. Die Fehler stammen aus 2023, seitdem wurden die Tests nicht mehr ausgeführt.
  • Zeilenabdeckung 6,1 %. Abgedeckt sind zwei Hilfsklassen und das Login-Formular.
  • Kritische Pfade ohne Test: Buchung anlegen, Preisberechnung, Rechnungserzeugung (PDF), Callback des Zahlungsanbieters, Authentifizierung der Fahrer-API, monatlicher Rechnungsexport (XLSX).
  • Keine CI-Pipeline. deploy.sh führt auf der Produktion git pull, composer install (ohne --no-dev, deshalb liegen Ignition und Faker auf den Servern) und php artisan migrate --force aus, in dieser Reihenfolge und ohne Backup-Schritt.

4.3 Statische Codeanalyse und Upgrade-Fähigkeit

PrüfungErgebnis
PHPStan Level 0 (ohne Laravel-Erweiterung)286 Fehler. 41 davon sind Aufrufe nicht definierter Methoden oder Funktionen, mindestens 7 davon auf Codepfaden, die über Routen erreichbar sind
PHPStan Level 5 (ohne Laravel-Erweiterung)1.912 Fehler. Wir empfehlen eine Baseline auf Level 5 und ab Etappe 1 keine neuen Fehler
PHPCompatibility, Ziel PHP 8.437 Fehler, 112 Warnungen
Rector-Probelauf, Regelsatz PHP 8.1214 Dateien würden sich ändern; rund 80 % davon mechanisch (Constructor Promotion, str_contains, Nullsafe-Aufrufe)

Was PHP 8 im Weg steht, in der Reihenfolge, in der es auftreten würde:

  1. app/Libraries/LegacyCsv.php verwendet each(), das in PHP 8.0 entfernt wurde. Die Klasse wird vom monatlichen Import genutzt: ein Fatal Error beim ersten Lauf nach dem Upgrade.
  2. 23 Klassen nutzen dynamische Properties (seit PHP 8.2 deprecated), vor allem in app/Services/Pricing/.
  3. String-Interpolation mit ${…} (Dollarzeichen außerhalb der Klammern) an 31 Stellen (seit PHP 8.2 deprecated).
  4. Implizit nullable Parameter in 58 Methodensignaturen (seit PHP 8.4 deprecated).
  5. Laravel 6 läuft höchstens auf PHP 8.0, deshalb müssen PHP- und Framework-Upgrade verzahnt werden (Abschnitt 6).

Hotspots

Die in den letzten 24 Monaten am häufigsten geänderten Dateien, mit ihrer Größe.

DateiZeilenCommits (24 Monate)Anmerkung
app/Http/Controllers/BookingController.php2.14061Preisberechnung, Validierung und E-Mail in einer Klasse; erster Kandidat für Charakterisierungstests
app/Services/InvoiceService.php1.31038PDF-Erzeugung, Nummerierung, Umsatzsteuer; die Nummerierung nutzt MAX(id)+1 ohne Sperre
app/Http/Controllers/Api/DriverController.php87029JWT-Verarbeitung, von Hand um php-jwt herum geschrieben

4.4 Konfiguration und Sicherheit

IDBefundNachweisEmpfehlung
C1Staging ist öffentlich, APP_DEBUG=true, Ignition installiertstaging.acme-fleet.example antwortet ohne Authentifizierungheute per IP oder HTTP-Auth einschränken; APP_DEBUG=false setzen; mit --no-dev deployen
C2Die Staging-Datenbank ist eine wöchentliche Kopie der Produktion mit personenbezogenen DatenCronjob refresh-staging.shdurch eine anonymisierte Kopie ersetzen; das ist auch ein DSGVO-Thema
C3Secrets in der Historiegitleaks: .env.production im März 2021 committet und in einem späteren Commit entfernt; enthält APP_KEY, DB_PASSWORD, MAIL_PASSWORDalle drei rotieren; siehe den Hinweis zu APP_KEY unten
C4Trusted Proxies auf * gesetztapp/Http/Middleware/TrustProxies.phpdie Adresse des Load Balancers eintragen; heute kann jeder Client über X-Forwarded-For seine eigene IP setzen und so das Rate Limit beim Login aushebeln
C5Session-Cookie ohne Secure-Flag, kein HSTSSESSION_SECURE_COOKIE nicht gesetzt; kein Header Strict-Transport-Securitybeides setzen, nachdem HTTPS überall bestätigt ist
C6Remote-Ressourcen in dompdf aktiviertconfig/dompdf.php: enable_remote => truedas Logo als lokale Datei einbinden und Remote-Zugriff abschalten
C7Queue-Worker wird jede Minute per Cron gestartet, als rootcrontab -l für rootunter Supervisor oder systemd als Anwendungsbenutzer betreiben
C8Backups: nächtlicher mysqldump nach /var/backups auf demselben Servercrontab, VerzeichnislisteKopie außer Haus, Verschlüsselung, monatlicher Wiederherstellungstest
C9Die JWT-Prüfung übernimmt den Algorithmus aus dem Token-HeaderDriverController::decodeToken()wird mit dem Upgrade auf php-jwt 6 erledigt; den Handler im selben Schritt korrigieren

Zum Rotieren von APP_KEY

Laravel nutzt diesen Schlüssel für verschlüsselte Cookies, signierte URLs und alle Werte, die Ihr Code mit Crypt::encrypt() oder encrypt() verschlüsselt. Ein neuer Schlüssel meldet alle Benutzer ab und macht diese Werte unlesbar, wenn sie nicht neu verschlüsselt werden. Das Portal speichert ein solches Feld (die Ausweisnummern der Fahrer, verschlüsselt in einem Model-Mutator). Zu Etappe 0 gehört ein kurzes Skript, das mit dem alten Schlüssel entschlüsselt und mit dem neuen wieder verschlüsselt.

4.5 Laufzeitumgebung

Der Produktionsserver läuft mit Ubuntu 20.04 und dem PHP-7.4-Paket der Distribution. Die reguläre Sicherheitswartung von Ubuntu für 20.04 endete im Mai 2025. Der Server ist nicht an Ubuntu Pro angebunden, das PHP-Paket und der Rest des Betriebssystems bekommen also keine Sicherheitsupdates.

Mit Ubuntu Pro gäbe es sie wieder, bis Mai 2030, für die Pakete aus dem Main-Repository von Ubuntu, zu denen PHP 7.4 gehört. Das behebt nur die Laufzeitumgebung, an Laravel und den Paketen aus Abschnitt 4.1 ändert es nichts.

4.6 Was in gutem Zustand ist

  • Die Datenbankmigrationen bauen das komplette Schema fehlerfrei aus einer leeren Datenbank auf. Eine reproduzierbare Umgebung braucht also kein manuelles SQL.
  • Der Callback des Zahlungsanbieters prüft dessen Signatur, bevor er eine Bestellung ändert.
  • Die Anwendung nutzt die Queues, den Scheduler und die Mail-Komponenten von Laravel ohne eigene Ersatzlösungen. Das Upgrade kann deshalb den offiziellen Upgrade-Guides folgen.

5. Prioritäten

PrioritätWasWarum zuerst
P0, diese WocheC1, C2, C3, C6, C8jetzt ausnutzbar oder würde einen Vorfall unumkehrbar machen
P0, diese Wochelaravel/framework 6.20.0 → 6.20.45, league/flysystem → 1.1.4, guzzlehttp/guzzle → 6.5.8, guzzlehttp/psr7 → 1.9.1Patch-Releases ohne Wechsel der Major-Version, geringes Risiko auch ohne Tests
P1, Etappe 1Tests für die sechs kritischen Pfade, CI, Runbook, Monitoring, C4, C5, C7, Ubuntu Pro oder ein neuer Serverohne das lässt sich nichts anderes sicher ändern
P2, Etappen 2–3Upgrade von PHP und Laravel, Ersatz nicht mehr gepflegter Pakete, C9braucht das Sicherheitsnetz aus Etappe 1

6. Plan und Festpreise

Die Preise in diesem Beispiel orientieren sich an unseren veröffentlichten Einstiegspreisen. Ein echtes Audit endet mit einem Angebot wie diesem, mit Festpreisen für den darin beschriebenen Umfang.

Option A (empfohlen): erst das Sicherheitsnetz, dann Laravel 13 auf PHP 8.4

Etappen 1–3 zusammen: ein Takeover M und zwei Upgrade-M-Etappen, rund vier Monate. Ergebnis: Laravel 13 (Sicherheitsupdates bis 17. März 2028) auf PHP 8.4 (Sicherheitsupdates bis 31. Dezember 2028), Tests für jeden kritischen Pfad, CI bei jeder Änderung und ein Runbook, mit dem auch ein anderer Entwickler arbeiten kann.
EtappeUmfangDauerFestpreisZahlung
0. Eindämmendie in Abschnitt 5 mit P0 markierten Punkte; Ihr Team kann sie mit unserer Schritt-für-Schritt-Anleitung in 1–2 Tagen umsetzen, oder wir erledigen sie in der ersten Woche von Etappe 11 Wochein Etappe 1 enthaltenmit Etappe 1
1. TakeoverDocker-Umgebung, die die Produktion abbildet; CI; Charakterisierungstests für die sechs kritischen Pfade; PHPStan-Baseline auf Level 5; Backups außer Haus mit Wiederherstellungstest; Monitoring; Runbook und Architekturübersicht; Übersicht aller Zugänge4 Wochen (Größe M)3.000 €100 % bei Auftrag
2. Upgrade ILaravel 6 → 9 und PHP 7.4 → 8.1 in Schritten (6 → 8 auf PHP 7.4, dann PHP 8.0, dann Laravel 9 auf PHP 8.1); SwiftMailer → Symfony Mailer; php-jwt 6 mit Korrektur des JWT-Handlers; dompdf 2.x; Guzzle 7; Faker → fakerphp/faker; LegacyCsv neu geschrieben6 Wochen6.000 €30 % / 70 % nach grüner CI und Ihrer Abnahme auf Staging
3. Upgrade IILaravel 9 → 13 und PHP 8.1 → 8.4; Server auf Ubuntu 24.04; phpspreadsheet und dompdf auf aktuelle Versionen; fideloper/proxy entfernt; dynamische Properties und Deprecations bereinigt6 Wochen6.000 €30 % / 70 % nach grüner CI und Ihrer Abnahme auf Staging
Care Standardmonatliche Updates von PHP und Abhängigkeiten, Monitoring, 8 Stunden für Änderungen, Reaktion auf kritische Störungen innerhalb von 4 Stunden in der Geschäftszeit, Quartalsreviewab Monat 5800 €/Monatmonatlich

Option B: 12 Monate sicher auf der aktuellen Version betreiben

Etappe 0 und Etappe 1 wie oben (3.000 €), Ubuntu Pro auf dem bestehenden Server für Patches der Laufzeitumgebung (das Abonnement zahlen Sie direkt an Canonical), die Patch-Releases aus Abschnitt 5 und Care Basic für 400 € im Monat.

So bleiben die offensichtlichen Lücken geschlossen, während Sie über die Zukunft der Anwendung entscheiden. Nicht beseitigt werden damit die 5 Laravel-Advisories ohne Fix auf der 6.x-Linie, die Lücken in dompdf und phpspreadsheet, die Major-Upgrades erfordern, und die Hindernisse für PHP 8. Nach 12 Monaten kostet Option A ungefähr so viel wie heute, zuzüglich der neuen Advisories, die bis dahin erscheinen.

Option B ist sinnvoll, wenn das Portal innerhalb von 18 Monaten ersetzt oder abgeschaltet wird oder das Budget für dieses Jahr feststeht.

Option C: Neuentwicklung

Davon raten wir ab. Die Geschäftsregeln des Portals (Preisberechnung, Rechnungsnummerierung, Umsatzsteuer) existieren nur im Code, und keine davon ist getestet. Eine Neuentwicklung müsste sie erst wiederentdecken, und das alte System bräuchte während der Entwicklung trotzdem Option B.

7. Was wir von Ihnen für den Start brauchen

  1. Eine Entscheidung für Option A oder B.
  2. Für Etappe 0: jemanden mit Admin-Zugriff auf Staging und die Datenbank, der die Passwörter gemeinsam mit uns rotiert, im Call oder per E-Mail.
  3. Für Etappe 1: personalisierte Konten für uns im Git-Hosting und auf Staging und eine Person, die sagen kann, was die sechs kritischen Pfade tun sollen, wenn Code und Anwender sich widersprechen.

Anhang A: vollständiger Abhängigkeitsscan. Die komplette Ausgabe von composer audit (JSON, alle 114 Advisories) liefern wir mit dem Bericht als separate Datei.

Der Bericht und alle Befunde sind vertraulich und fallen unter die NDA.

Wie ein so ausführlicher Bericht in den Preis passt

Werkzeuge zählen, wir lesen den Code. KI-Werkzeuge, mit Ihrer schriftlichen Zustimmung eingesetzt, beschleunigen das Lesen und die Prüfungen; ein Entwickler prüft jeden Befund, bevor er in den Bericht kommt. Mehr dazu unter Arbeitsweise und Sicherheit und Vertrauen.

Möchten Sie einen solchen Bericht für Ihre Anwendung?

Code Audit ab 800 €, Bericht in 5–7 Arbeitstagen. Noch unsicher? Beginnen Sie mit einem Debt Check für 300 €.