Przykładowy raport

Tak wygląda raport z Code Audit, od pierwszej do ostatniej strony.

Kompletny przykładowy raport dla fikcyjnej aplikacji. Zobaczysz strukturę i szczegółowość, zanim zamówisz własny. Aplikacja jest zmyślona, ale dane o podatnościach pochodzą z prawdziwego przebiegu composer audit.

Przykład dla fikcyjnej aplikacji. Firma Acme Logistics i Acme Fleet Portal nie istnieją.

Przykładowy raport, fikcyjna aplikacja

„Acme Fleet Portal” i Acme Logistics nie istnieją. Kod, metryki i ustalenia dotyczące konfiguracji w tym raporcie są zmyślone, żeby pokazać strukturę i szczegółowość Code Audit w Refbergu. Dane o podatnościach są prawdziwe: 24 października 2026 uruchomiliśmy composer audit na pliku lock z wersjami paczek wymienionymi w punkcie 4.1. Liczby zgłoszeń, identyfikatory CVE i wersje z poprawkami pochodzą z tego przebiegu. Ceny to przykłady oparte na naszych opublikowanych cenach wyjściowych.

Raport z Code Audit

KlientAcme Logistics Sp. z o.o. (firma fikcyjna)
AplikacjaAcme Fleet Portal: rezerwacje, fakturowanie i API JSON dla aplikacji mobilnej kierowców
Rozmiar audytuM (od 50 000 do 200 000 linii kodu PHP)
Dostęprepozytorium tylko do odczytu, pliki .env stagingu i produkcji (z usuniętymi sekretami), pliki konfiguracyjne serwera, crontab
Data24 października 2026
PrzygotowałRefberg

1. Podsumowanie dla zarządu

Portal działa i zarabia, ale stoi na oprogramowaniu, które przestało dostawać poprawki bezpieczeństwa między 2022 a 2025 rokiem. Trzy problemy wymagają działania jeszcze w tym tygodniu, przed jakąkolwiek aktualizacją:

  1. Serwer stagingowy można przejąć z internetu. Jest publicznie dostępny, działa w trybie debugowania i ma komponent z opublikowaną luką pozwalającą na zdalne wykonanie kodu (CVE-2021-3129). Na stagingu leży cotygodniowa kopia produkcyjnej bazy danych, razem z nazwiskami, adresami i fakturami klientów.
  2. Hasła produkcyjne i klucz szyfrowania aplikacji są w historii Git. Może je odczytać każdy, kto ma albo kiedykolwiek miał kopię repozytorium. Nie były zmieniane od 2021 roku.
  3. Kopie zapasowe leżą na tym samym serwerze co baza danych i nigdy nie zostały odtworzone. Awaria dysku albo ransomware na tym serwerze zabrałyby dane razem z kopiami.

Wszystkie trzy da się zamknąć w jeden do dwóch dni, bez zmian w kodzie aplikacji (punkt 6, etap 0).

Problem długoterminowy to sama platforma: PHP 7.4 (koniec wsparcia: 28 listopada 2022) i Laravel 6 (koniec poprawek bezpieczeństwa: 6 września 2022). Skan zależności znalazł 114 opublikowanych zgłoszeń bezpieczeństwa w 20 paczkach. Część da się załatać wydaniami poprawkowymi w obrębie Laravela 6. Większość wymaga aktualizacji.

Testów automatycznych prawie nie ma (6,1% pokrycia linii, żadnego testu na sześciu krytycznych ścieżkach biznesowych), więc każda zmiana jest dziś strzałem na ślepo. Rekomendujemy wariant A: najpierw siatka bezpieczeństwa, potem aktualizacja w dwóch etapach ze stałą ceną do Laravela 13 na PHP 8.4, w ciągu około czterech miesięcy, a od 5. miesiąca Care Standard. Wariant B (zostać na Laravelu 6 z łatanym PHP) kosztuje w tym roku mniej. Punkt 6 wyjaśnia, kiedy ma sens.

2. Zakres i metoda

W zakresie: kod aplikacji w repozytorium (gałąź main, commit 4f1c9e2), composer.json i composer.lock, historia Git, pliki konfiguracyjne, konfiguracja serwera przekazana przez klienta, skrypt wdrożeniowy.

Narzędzia: composer audit (Composer 2, baza zgłoszeń Packagist), PHPStan 2.x bez rozszerzenia dla Laravela (Larastan dla Laravela 6 istnieje tylko dla starej linii PHPStan 0.12, więc analizę z Larastanem powtarzamy po aktualizacji frameworka), Rector 2.x w trybie dry run, PHP_CodeSniffer z PHPCompatibility, PHPUnit z PCOV do pomiaru pokrycia, gitleaks do szukania sekretów w historii, git log do częstotliwości zmian. Potem ręczny przegląd routingu, uwierzytelniania, przesyłania plików, generowania PDF, kolejek i zadań cyklicznych.

Poza zakresem: testy penetracyjne, testy obciążeniowe, przegląd aplikacji mobilnej, systemy operatora płatności i konfiguracja sieci u dostawcy hostingu. Niczego nie próbowaliśmy wykorzystać. Gdy piszemy, że podatność jest możliwa do wykorzystania, mamy na myśli, że w Twojej konfiguracji spełnione są jej opublikowane warunki.

3. Mapa ryzyk

Prawdopodobieństwo i skutek oceniamy w skali od 1 (niski) do 3 (wysoki). Priorytet: P0 w tym tygodniu, P1 w pierwszym etapie, P2 w trakcie aktualizacji.

IDRyzykoPrawdopodobieństwoSkutekPriorytet
R1Zdalne wykonanie kodu na publicznym stagingu przez Ignition (CVE-2021-3129); na stagingu są produkcyjne dane osobowe33P0
R2APP_KEY oraz hasła do bazy i poczty widoczne w historii Git od 2021 roku33P0
R3Kopie zapasowe na tym samym serwerze, nigdy nieodtworzone23P0
R4Generowanie PDF z włączonymi zasobami zdalnymi w dompdf 0.8.6 (CVE-2022-28368, zdalne wstrzyknięcie kodu przez czcionki)23P0
R5Brak testów na krytycznych ścieżkach; 9 z 42 istniejących testów nie przechodzi32P1
R6PHP 7.4 z Ubuntu 20.04 bez Ubuntu Pro: od maja 2025 brak aktualizacji bezpieczeństwa środowiska uruchomieniowego23P1
R7Laravel 6 po końcu wsparcia; 5 zgłoszeń dotyczących frameworka nie ma poprawki w linii 6.x22P2
R8Porzucone lub zastąpione paczki (SwiftMailer, Faker, Ignition 1.x)22P2
R9Całą wiedzę miał jeden były programista; brak runbooka, wdrożenie to skrypt shell uruchamiany ręcznie32P1

4.1 Zależności

Wynik: 114 zgłoszeń w 20 paczkach: 13 krytycznych, 44 wysokie, 50 średnich, 7 niskich. 110 z nich dotyczy zależności produkcyjnych. Wybrane paczki:

PaczkaZainstalowanaZgłoszeniaNajważniejsze zgłoszeniaPierwsza wersja z poprawkąDo naprawy w obrębie Laravela 6?
laravel/framework6.20.011CVE-2021-21263 (wiązanie parametrów zapytań), CVE-2021-43808 (XSS w Blade), CVE-2024-52301 (środowisko przez query string)6.20.45 dla 6 z 11częściowo: 6.20.45
facade/ignition (dev)1.16.33CVE-2021-3129 (zdalne wykonanie kodu)1.16.14 (1.16.15 dla wszystkich trzech)tak; poza tym nie może być zainstalowana na produkcji
dompdf/dompdf0.8.614CVE-2022-28368 (zdalne wstrzyknięcie kodu przez czcionki), CVE-2021-3838 (deserializacja)1.2.1 / 2.0.x / 3.1.6częściowo: wymaga aktualizacji laravel-dompdf do nowej wersji głównej
guzzlehttp/guzzle6.5.514CVE-2022-31090, CVE-2022-31091 (dane uwierzytelniające zachowane po przekierowaniu do innej domeny)6.5.8 dla 5 z 14częściowo
firebase/php-jwt5.2.02CVE-2021-46743 (pomylenie klucza i algorytmu)6.0.0tak, ze zmianami w kodzie (nowe API)
league/flysystem1.0.702CVE-2021-32708 (race condition przy zapisie plików)1.1.4tak
phpoffice/phpspreadsheet1.15.029XXE w czytniku XLSX (CVE-2024-45293, CVE-2024-48917)1.29.4 i nowsze (dla obu luk XXE)prawdopodobnie, przez nowszy maatwebsite/excel 3.1.x; do potwierdzenia w etapie 1
swiftmailer/swiftmailer6.2.31CVE-2024-28859 (gadżet deserializacji)6.2.5tak, ale paczka jest porzucona

Porzucone lub zastąpione: swiftmailer/swiftmailer jest oznaczony na Packagist jako porzucony na rzecz symfony/mailer (Laravel 9 przeszedł na niego). fzaninotto/faker jest oznaczony jako porzucony. facade/ignition zastąpił spatie/laravel-ignition; ostatnie wydanie ukazało się w styczniu 2023. fideloper/proxy nie miał wydania od lutego 2022, a jego funkcje przeszły do Laravela 9.

Dlaczego to ważniejsze niż sama liczba: groźne są te zgłoszenia, których warunki spełniasz. W tej aplikacji to Ignition na stagingu (R1, tryb debugowania jest włączony), dompdf z enable_remote => true w config/dompdf.php (R4, szablon faktury ładuje logo z adresu URL) i php-jwt w API mobilnym (bez wglądu w konfigurację kluczy nie mogliśmy potwierdzić, czy lukę da się wykorzystać; patrz 4.4).

4.2 Testy i CI

  • 42 testy PHPUnit, z czego 9 nie przechodzi na main. Błędy pochodzą z 2023 roku i od tego czasu nikt testów nie uruchamiał.
  • Pokrycie linii 6,1%. Pokryte są dwie klasy pomocnicze i formularz logowania.
  • Krytyczne ścieżki bez żadnego testu: tworzenie rezerwacji, wyliczanie ceny, generowanie faktury (PDF), callback płatności, uwierzytelnianie w API kierowców, miesięczny eksport faktur (XLSX).
  • Brak pipeline'u CI. deploy.sh uruchamia na produkcji git pull, composer install (bez --no-dev, dlatego Ignition i Faker są na serwerach) i php artisan migrate --force, w tej kolejności i bez kroku kopii zapasowej.

4.3 Analiza statyczna i gotowość do aktualizacji

SprawdzenieWynik
PHPStan, poziom 0 (bez rozszerzenia dla Laravela)286 błędów. 41 to wywołania niezdefiniowanych metod lub funkcji, z czego co najmniej 7 na ścieżkach osiągalnych z routingu
PHPStan, poziom 5 (bez rozszerzenia dla Laravela)1912 błędów. Rekomendujemy baseline na poziomie 5 i zero nowych błędów od etapu 1
PHPCompatibility, cel PHP 8.437 błędów, 112 ostrzeżeń
Rector dry run, zestaw reguł PHP 8.1zmieniłby 214 plików; około 80% to zmiany mechaniczne (constructor promotion, str_contains, operator nullsafe)

Blokery przed PHP 8, w kolejności, w jakiej wyjdą:

  1. app/Libraries/LegacyCsv.php używa each(), usuniętej w PHP 8.0. Z tej klasy korzysta miesięczny import: błąd krytyczny przy pierwszym uruchomieniu po aktualizacji.
  2. 23 klasy używają dynamicznych właściwości (deprecated w PHP 8.2), głównie w app/Services/Pricing/.
  3. Interpolacja ${…} w stringach (znak dolara przed klamrą) w 31 miejscach (deprecated w PHP 8.2).
  4. Niejawnie nullowalne parametry w 58 sygnaturach metod (deprecated w PHP 8.4).
  5. Laravel 6 działa najwyżej na PHP 8.0, więc aktualizacje PHP i frameworka trzeba przeplatać (punkt 6).

Hotspoty

Pliki najczęściej zmieniane w ostatnich 24 miesiącach, z ich rozmiarem.

PlikLinieCommity (24 miesiące)Uwagi
app/Http/Controllers/BookingController.php214061wyliczanie ceny, walidacja i e-maile w jednej klasie; pierwszy kandydat do testów charakteryzujących
app/Services/InvoiceService.php131038generowanie PDF, numeracja, VAT; numeracja korzysta z MAX(id)+1 bez blokady
app/Http/Controllers/Api/DriverController.php87029obsługa JWT napisana ręcznie wokół php-jwt

4.4 Konfiguracja i bezpieczeństwo

IDUstalenieDowódZalecenie
C1Staging jest publiczny, APP_DEBUG=true, zainstalowany Ignitionstaging.acme-fleet.example odpowiada bez uwierzytelnieniajeszcze dziś ograniczyć dostęp po IP albo HTTP auth; ustawić APP_DEBUG=false; wdrażać z --no-dev
C2Baza stagingu to cotygodniowa kopia produkcji z danymi osobowymizadanie cron refresh-staging.shzastąpić kopią zanonimizowaną; to także problem z RODO
C3Sekrety w historiigitleaks: .env.production zacommitowany w marcu 2021 i usunięty w późniejszym commicie; zawiera APP_KEY, DB_PASSWORD, MAIL_PASSWORDzmienić wszystkie trzy; patrz uwaga o APP_KEY poniżej
C4Zaufane proxy ustawione na *app/Http/Middleware/TrustProxies.phpwpisać adres load balancera; dziś każdy klient może podać własne IP w X-Forwarded-For, co omija limit prób logowania
C5Ciasteczko sesji bez flagi Secure, brak HSTSSESSION_SECURE_COOKIE nieustawione; brak nagłówka Strict-Transport-Securityustawić oba po potwierdzeniu, że HTTPS działa wszędzie
C6Zasoby zdalne w dompdf włączoneconfig/dompdf.php: enable_remote => trueosadzić logo jako plik lokalny i wyłączyć zasoby zdalne
C7Worker kolejki uruchamiany z crona co minutę, jako rootcrontab -l dla rootauruchamiać przez Supervisor albo systemd jako użytkownik aplikacji
C8Kopie zapasowe: nocny mysqldump do /var/backups na tym samym serwerzecrontab, listing dyskukopia poza serwerem, szyfrowanie, comiesięczny test odtworzenia
C9Weryfikacja JWT przyjmuje algorytm z nagłówka tokenuDriverController::decodeToken()obejmie to aktualizacja do php-jwt 6; przy okazji poprawić obsługę tokenów

O zmianie APP_KEY

Laravel używa tego klucza do szyfrowania ciasteczek, podpisywania adresów URL i do każdej wartości, którą Twój kod szyfruje przez Crypt::encrypt() albo encrypt(). Zmiana klucza wylogowuje wszystkich użytkowników, a te wartości stają się nieczytelne, jeśli nie zostaną zaszyfrowane ponownie. Portal przechowuje jedno takie pole (numery dokumentów tożsamości kierowców, szyfrowane w mutatorze modelu). Etap 0 obejmuje krótki skrypt, który odszyfrowuje dane starym kluczem i szyfruje je nowym.

4.5 Środowisko uruchomieniowe

Serwer produkcyjny działa na Ubuntu 20.04 z pakietem PHP 7.4 z dystrybucji. Standardowe wsparcie bezpieczeństwa Ubuntu 20.04 skończyło się w maju 2025. Serwer nie jest podłączony do Ubuntu Pro, więc ani pakiet PHP, ani reszta systemu operacyjnego nie dostają aktualizacji bezpieczeństwa.

Podłączenie serwera do Ubuntu Pro przywróciłoby je do maja 2030 dla pakietów z głównego repozytorium Ubuntu, w którym jest PHP 7.4. To naprawia tylko środowisko uruchomieniowe. Nie zmienia niczego w Laravelu ani w paczkach z punktu 4.1.

4.6 Co jest w dobrym stanie

  • Migracje bazy danych odtwarzają cały schemat od pustej bazy bez błędów, więc powtarzalne środowisko nie wymaga ręcznego SQL.
  • Callback płatności weryfikuje podpis operatora, zanim zmieni zamówienie.
  • Aplikacja korzysta z wbudowanych w Laravela kolejek, harmonogramu zadań i poczty, bez własnych zamienników, więc ścieżka aktualizacji idzie zgodnie z oficjalnymi przewodnikami.

5. Priorytety

PriorytetCoDlaczego najpierw
P0, w tym tygodniuC1, C2, C3, C6, C8da się to wykorzystać już teraz albo uniemożliwiłoby odtworzenie danych po incydencie
P0, w tym tygodniularavel/framework 6.20.0 → 6.20.45, league/flysystem → 1.1.4, guzzlehttp/guzzle → 6.5.8, guzzlehttp/psr7 → 1.9.1wydania poprawkowe w tej samej wersji głównej, niskie ryzyko nawet bez testów
P1, etap 1testy na sześciu krytycznych ścieżkach, CI, runbook, monitoring, C4, C5, C7, Ubuntu Pro albo nowy serwerbez tego niczego innego nie da się bezpiecznie zmienić
P2, etapy 2–3aktualizacja PHP i Laravela, wymiana porzuconych paczek, C9wymaga siatki testów z etapu 1

6. Plan i stałe ceny

Ceny w tym przykładzie są oparte na naszych opublikowanych cenach wyjściowych. Prawdziwy audyt kończy się taką ofertą jak ta, z cenami stałymi dla określonego w niej zakresu.

Wariant A (rekomendowany): siatka bezpieczeństwa, potem Laravel 13 na PHP 8.4

Etapy 1–3 razem: jeden Takeover M i dwa etapy aktualizacji w rozmiarze M, około czterech miesięcy. Stan końcowy: Laravel 13 (poprawki bezpieczeństwa do 17 marca 2028) na PHP 8.4 (wsparcie bezpieczeństwa do 31 grudnia 2028), testy na każdej krytycznej ścieżce, CI przy każdej zmianie i runbook, z którego skorzysta inny programista.
EtapZakresCzasStała cenaPłatność
0. Ograniczenie ryzykapozycje z priorytetem P0 z punktu 5; Twój zespół może je wykonać w 1–2 dni według naszej instrukcji krok po kroku albo zrobimy to sami w pierwszym tygodniu etapu 11 tydzieńw cenie etapu 1razem z etapem 1
1. Przejęcie aplikacjiśrodowisko Docker odtwarzające produkcję; CI; testy charakteryzujące dla sześciu krytycznych ścieżek; baseline PHPStan na poziomie 5; kopie zapasowe poza serwerem z testem odtworzenia; monitoring; runbook i mapa architektury; inwentarz dostępów4 tygodnie (rozmiar M)13 000 zł100% przy zamówieniu
2. Aktualizacja ILaravel 6 → 9 i PHP 7.4 → 8.1 krokami (6 → 8 na PHP 7.4, potem PHP 8.0, potem Laravel 9 na PHP 8.1); SwiftMailer → Symfony Mailer; php-jwt 6 z poprawką obsługi JWT; dompdf 2.x; Guzzle 7; Faker → fakerphp/faker; przepisanie LegacyCsv6 tygodni26 000 zł30% / 70% po zielonym CI i Twojej akceptacji na stagingu
3. Aktualizacja IILaravel 9 → 13 i PHP 8.1 → 8.4; serwer z Ubuntu 24.04; phpspreadsheet i dompdf do aktualnych wersji; usunięcie fideloper/proxy; usunięte dynamiczne właściwości i deprecations6 tygodni26 000 zł30% / 70% po zielonym CI i Twojej akceptacji na stagingu
Care Standardcomiesięczne aktualizacje PHP i zależności, monitoring, 8 godzin na zmiany, reakcja na krytyczne zgłoszenia w ciągu 4 godzin roboczych, kwartalny przeglądod 5. miesiąca3500 zł/mies.co miesiąc

Wariant B: utrzymać obecną wersję w bezpiecznym stanie przez 12 miesięcy

Etap 0 i etap 1 jak wyżej (13 000 zł), Ubuntu Pro na obecnym serwerze dla poprawek środowiska uruchomieniowego (subskrypcję opłacasz bezpośrednio w Canonical), wydania poprawkowe z punktu 5 i Care Basic za 1700 zł miesięcznie.

To zamyka oczywiste dziury, zanim zdecydujesz o przyszłości aplikacji. Nie usuwa jednak 5 zgłoszeń dotyczących Laravela, które nie mają poprawki w linii 6.x, problemów z dompdf i phpspreadsheet wymagających aktualizacji do nowych wersji głównych ani blokerów przed PHP 8. Za 12 miesięcy wariant A będzie kosztował mniej więcej tyle co dziś, plus to, co przyniosą nowe zgłoszenia.

Wariant B ma sens, jeśli portal zostanie zastąpiony albo wyłączony w ciągu 18 miesięcy albo jeśli budżet na ten rok jest już zamknięty.

Wariant C: przepisanie od nowa

Nie rekomendujemy. Reguły biznesowe portalu (wyliczanie cen, numeracja faktur, obsługa VAT) istnieją tylko w kodzie i żadna nie jest przetestowana. Przepisanie oznaczałoby odkrywanie ich od nowa, a stary system i tak potrzebowałby wariantu B przez cały czas budowy nowego.

7. Czego potrzebujemy od Ciebie na start

  1. Decyzji: wariant A albo B.
  2. Do etapu 0: osoby z dostępem administratora do stagingu i bazy danych, która razem z nami zmieni hasła, w rozmowie albo e-mailem.
  3. Do etapu 1: imiennych kont dla nas w hostingu Git i na stagingu oraz osoby, która rozstrzygnie, jak ma działać każda z sześciu krytycznych ścieżek, gdy kod i użytkownicy mówią co innego.

Załącznik A: pełny skan zależności. Kompletny wynik composer audit (JSON, wszystkie 114 zgłoszeń) dostajesz razem z raportem jako osobny plik.

Raport i wszystkie ustalenia są poufne i objęte NDA.

Jak tak szczegółowy raport mieści się w cenie

Narzędzia liczą, a kod czytamy my. Narzędzia AI do programowania, używane za Twoją pisemną zgodą, przyspieszają czytanie i sprawdzanie. Każde ustalenie przegląda inżynier, zanim trafi do raportu. Więcej w Jak pracujemy i Bezpieczeństwo i zaufanie.

Chcesz taki raport dla swojej aplikacji?

Code Audit od 3500 zł, raport w 5–7 dni roboczych. Jeszcze nie wiesz? Zacznij od Debt Check za 1300 zł.