Zrobiliśmy sobie pentesty na ipIII (RED — 9 wektorów read-only) i poprosiliśmy niezależnego pentestera (r0xk0n) o drugą rundę. Ta strona pokazuje CO testowano i JAKA obrona zadziałała — bez payloadów ofensywnych, bez instrukcji ataku. Wynik i mitigacje poniżej, jawnie z odróżnieniem tego, co naprawiono.
noindex — to log ćwiczenia, nie oferta handlowa.
Metodologia: każdy wektor testowany read-only lub niedestrukcyjnym probe, wynik weryfikowany przez adwersaryjny werdykt (druga rola próbuje obalić ustalenie), zanim trafi do tego rejestru jako „broni się" albo jako finding do naprawy. To NIE jest deklaracja nieprzenikalności systemu — to raport z konkretnego, ograniczonego zakresu testów na dzień weryfikacji.
Wyłącznie read-only i niedestrukcyjne probe na własnym środowisku. Bez ofensywnych payloadów, bez prób obejścia mechanizmów obronnych na cudzej infrastrukturze. Data weryfikacji: 2026-07-05.
Próby ominięcia uwierzytelniania (brak tokenu, zmanipulowany token, algorithm-confusion).
Dostęp do zasobu innego tenanta/organizacji przez zmianę identyfikatora w żądaniu.
Próby wstrzyknięcia w zapytania SQL, formuły CSV, parsowanie XML.
Szukanie sekretów zaszytych w kodzie, logach, odpowiedziach błędów.
Sprawdzenie polityki CSP, obecności inline JS, kompletu nagłówków bezpieczeństwa.
Test limitów żądań, zachowania za proxy, ochrony przed pętlami.
Fuzzing parserów importu (skanery, CSV, XML) losowymi/zniekształconymi danymi.
Walidacja pól wejściowych, limity długości, typy danych.
Sprawdzenie, czy błędy/odpowiedzi ujawniają stack-trace, wersje, ścieżki serwera.
Kolumna „Obrona" opisuje wyłącznie CO chroni (mechanizm), nie jak go obejść. Zero szczegółów ofensywnych.
| Wektor | Obrona zaobserwowana | Wynik |
|---|---|---|
| Auth-bypass | Fail-closed: brak JWT_SECRET → proces zatrzymuje start (process.exit), nie uruchamia się w trybie niedomyślnie otwartym. OIDC RS256 wymuszony dwukrotnie (walidacja algorytmu w dwóch miejscach) — bez podatności typu algorithm-confusion. RBAC granularny per rola. |
broni się |
| IDOR / BOLA | tenantGuard zwraca 404 dla zasobu spoza kontekstu żądającego (nie ujawnia nawet istnienia obcego zasobu) — fail-closed zamiast fail-open. |
broni się |
| Injection (SQL/CSV/XXE) | Zapytania SQL wyłącznie parametryzowane ($1..$N, brak konkatenacji stringów). Parsery XML oparte o regex (brak silnika XML z zewnętrznymi encjami — XXE nieegzekwowalny w tej architekturze). Eksport CSV z formula-guard (prefiks neutralizujący przed =/+/-/@). |
broni się |
| Secrets-exposure | git grep po wzorcach sekretów w repo — pusty wynik. .env w .gitignore. W trybie PROD błędy zwracają generyczny safeError bez stack-trace i bez szczegółów implementacji. |
broni się |
| CSP / nagłówki | Nonce 128-bit generowany per-request, strict-dynamic, brak dopuszczonego inline JS bez nonce, HSTS z preload, komplet standardowych nagłówków bezpieczeństwa (X-Content-Type-Options, X-Frame-Options, Referrer-Policy). |
broni się |
| Rate-limit | Wielowarstwowe limity (globalny + per-endpoint), trust proxy skonfigurowany poprawnie (limit liczony po realnym IP, nie po adresie proxy), watcher wykrywający pętle żądań. |
broni się |
| Parser-safety | Limit rozmiaru body (body-cap) przed parsowaniem, zestaw testów fuzz 30/30 przechodzących bez crasha procesu, guardy wejścia przed przekazaniem do logiki biznesowej. | broni się |
| Input-validation | Walidacja typu/długości/formatu na wejściach API przed zapisem do bazy; odrzucenie zamiast próby „naprawienia" złych danych. | broni się |
| Info-leak | Odpowiedzi błędów w PROD generyczne (bez ścieżek serwera, wersji zależności, stack-trace); szczegóły trafiają wyłącznie do logów serwerowych. | broni się |
Poza wewnętrznym ćwiczeniem RED, zewnętrzny pentester (r0xk0n) przeprowadził dwie rundy testów. Znalazł realne findingi — zostały naprawione, nie ukryte. To dowód, że ćwiczenie wewnętrzne nie zastępuje niezależnej weryfikacji, a wyniki obu razem dają pełniejszy obraz.
| Runda | Finding | Naprawa |
|---|---|---|
| R2 | Izolacja multi-tenant: zapytania po organizacjach nie były w pełni scope'owane per tenant. | Scoping /orgs per-tenant + test IDOR cross-tenant weryfikujący fix. |
| R1/R2 | Pinning algorytmu w walidacji JWT. | Pin HS256 jawnie w walidatorze wewnętrznego JWT v1 (osobny mechanizm od OIDC/RS256 z wiersza Auth-bypass — każdy walidator przypięty do jednego algorytmu, brak algorithm-confusion między nimi). |
| R1 | Eksport CSV podatny na wstrzyknięcie formuł w arkuszu odbiorcy. | Formula-guard: prefiksowanie komórek zaczynających się od =/+/-/@. |
| R1 | Dowód (evidence) bez faktycznej treści mógł być traktowany jak zweryfikowany. | Dowód bez treści → status UNVERIFIED zamiast domyślnego zaliczenia. |
Wszystkie cztery pozycje: naprawione i domknięte w kodzie (commity powiązane z audytem R2 tenant-evidence). Rejestr nie ukrywa, że coś znaleziono — przeciwnie, to dowód działającego procesu evidence-first.
Drobny hardening do rozważenia (jawnie, nie ukrywamy): miejscami porównania sekretów/tokenów
mogłyby być bardziej konsekwentnie timing-safe (stałoczasowe) zamiast standardowego porównania
stringów — kandydat do kolejnej iteracji, nie potwierdzony dziś jako wykorzystywalny finding.
Ten raport to log ćwiczenia obronnego (co broni system). Symulacje scenariuszy ataku/obrony i
metodologii reagowania na incydent to osobna, dedykowana warstwa — wyraźnie oznaczona jako
SYMULACJA, noindex: