# SECURITY REPORT — TFM aInventory **Generat de:** Claude (Sonnet 4.6) **Data auditului:** 2026-04-11 **Versiune aplicație:** v1.3.5 (branch: dev) **Suprafețe auditate:** Backend (FastAPI), Frontend (Next.js/Dexie.js), Docker/Infra --- ## REZUMAT EXECUTIV Au fost identificate **12 vulnerabilități**, dintre care **4 CRITICE** care permit acces neautentificat complet la toate resursele API-ului. Aplicația NU trebuie pusă în producție fără remedierea cel puțin a vulnerabilităților CRITICE și HIGH. | Severitate | Nr. | Status | |------------|-----|--------| | 🔴 CRITIC | 4 | Nerezolvate | | 🟠 HIGH | 4 | Nerezolvate | | 🟡 MEDIUM | 3 | Nerezolvate | | 🔵 LOW | 1 | Nerezolvat | --- ## 🔴 VULNERABILITĂȚI CRITICE ### [C-01] ZERO Autentificare pe Toate Endpoint-urile API **Fișier:** `backend/routers/items.py`, `operations.py`, `categories.py`, `users.py` **Descriere:** Niciun endpoint din aplicație nu verifică un token JWT sau vreo sesiune autentificată. Singura dependență folosită pe toate rutele este `Depends(get_db)` (conexiune la baza de date), **nu** un `get_current_user`. Oricine cu acces la rețea poate: - Lista, crea, modifica, șterge orice produs (`/items/`) - Executa check-in/check-out/trash pe stocuri (`/operations/`) - Crea, lista, șterge utilizatori inclusiv admini (`/users/`) - Schimba configurația LDAP (`/users/ldap-config`) **Impact:** Compromitere totală a integrității datelor fără autentificare. **Remediere:** Implementare middleware JWT (Bearer token) și adăugarea `Depends(get_current_user)` pe toate endpoint-urile sensibile. **Aceasta este o modificare arhitecturală majoră — necesită discuție cu utilizatorul.** --- ### [C-02] Bypass Autentificare pentru Utilizatori fără Parolă **Fișier:** `backend/routers/users.py`, funcția `login` **Cod vulnerabil:** ```python elif user and not user.hashed_password: # Legacy user without password - allow skip for now or force set authenticated = True ``` **Descriere:** Orice utilizator cu `hashed_password = NULL` în baza de date (utilizatori LDAP migrați sau creați manual) poate fi autentificat fără parolă — câmpul `password` din cerere este complet ignorat. **Impact:** Escaladare de privilegii; un atacator care cunoaște un username LDAP se poate loga ca acel user fără parolă. **Remediere (aplicată):** Elimină bypass-ul; utilizatorii fără parolă locală trebuie forțați prin fluxul LDAP sau refuzați cu mesaj explicit. --- ### [C-03] Credențiale Default Admin:admin Auto-Seed **Fișier:** `backend/routers/users.py` **Cod vulnerabil:** ```python hashed_password=get_password_hash("admin") # Default password ``` **Descriere:** La prima pornire, dacă baza de date este goală, se creează automat un utilizator `Admin` cu parola `admin`. Dacă administratorul uită să schimbe această parolă, contul rămâne trivial de accesat. **Impact:** Acces admin imediat pe instalații noi sau resetate. **Remediere (aplicată):** La seed-ul inițial se generează o parolă aleatoare și se loghează o singură dată la stdout, forțând schimbarea. --- ### [C-04] GEMINI_API_KEY cu Valoare Reală în Fișierul .env **Fișier:** `backend/.env` **Descriere:** Fișierul `.env` conține o cheie API Google Gemini activă (`AIzaSy...`). Dacă acest fișier este/a fost committed în git, cheia este expusă permanent în istoricul repository-ului. **Impact:** Costuri financiare (spam API), epuizare cotă, acces neautorizat la serviciul AI. **Remediere imediată:** 1. Verificați `git log --all -- backend/.env` pentru a vedea dacă fișierul a fost committed. 2. Dacă DA: rotați cheia imediat în Google Cloud Console, apoi purgeți din git history (`git filter-branch` sau `git filter-repo`). 3. Asigurați-vă că `backend/.env` este în `.gitignore` (verificat — `.gitignore` există, dar trebuie confirmat că include `.env`). --- ## 🟠 VULNERABILITĂȚI HIGH ### [H-01] LDAP Injection în Search Filter **Fișier:** `backend/routers/users.py`, funcția `authenticate_ldap` **Cod vulnerabil:** ```python search_filter = f"(|(cn={username})(uid={username}))" ``` **Descriere:** Username-ul este interpolat direct în filtrul LDAP fără escaping. Un atacator poate injecta filtre LDAP arbitrare (ex: `*)(uid=*` sau `admin)(|(uid=*`). **Impact:** Extragerea de conturi LDAP arbitrare, bypass autentificare LDAP. **Remediere (aplicată):** Folosire `ldap3.utils.conv.escape_filter_chars(username)` înainte de interpolarea în filter. --- ### [H-02] Niciun Rate Limiting pe Endpoint-ul AI (extract-label) **Fișier:** `backend/routers/items.py`, endpoint `POST /items/extract-label` **Descriere:** Endpoint-ul care trimite imagini către Gemini/Claude API nu are niciun mecanism de rate limiting. Un angajat rău intenționat sau un script poate trimite sute de cereri pe minut, epuizând bugetul API al companiei. **Impact:** DoS financiar, epuizare cotă AI. **Remediere:** Adăugare `slowapi` rate limiter (ex: 10 req/min per IP). **Necesită instalare dependință — discutați cu utilizatorul.** --- ### [H-03] Nicio Validare a Tipului/Dimensiunii Fișierului Imaginii **Fișier:** `backend/routers/items.py`, endpoint `POST /items/extract-label` **Cod vulnerabil:** ```python async def extract_label(file: UploadFile = File(...)): contents = await file.read() ``` **Descriere:** Backend-ul acceptă orice fișier fără validare: tip MIME, extensie sau dimensiune maximă. Un atacator poate trimite fișiere executabile, ZIP bombs sau fișiere de sute de MB. **Impact:** DoS (memorie/CPU), injecție de conținut malițios. **Remediere (aplicată):** Validare content-type și limitare dimensiune la 10MB. --- ### [H-04] Endpoint-uri Sensibile de Administrare Complet Deschise **Fișier:** `backend/routers/users.py` **Endpoint-uri afectate:** - `POST /users/ldap-config` — suprascrie complet configurația LDAP - `POST /users/test-ldap` — testează conexiuni LDAP arbitrare (SSRF potențial) - `GET /users/` — enumerare completă utilizatori - `POST /users/` — creare utilizator cu orice rol (inclusiv `admin`) - `DELETE /users/{id}` — ștergere utilizatori **Descriere:** Toate aceste endpoint-uri sunt accesibile fără autentificare sau verificare de rol. **Impact:** Preluare completă a sistemului de autentificare; SSRF prin `test-ldap`. **Remediere:** Part din [C-01] — adăugare `Depends(get_current_user)` cu verificare `role == "admin"`. --- ## 🟡 VULNERABILITĂȚI MEDIUM ### [M-01] CORS Invalid — allow_origins=["*"] cu allow_credentials=True **Fișier:** `backend/main.py` **Cod vulnerabil:** ```python allow_origins=["*"], allow_credentials=True, ``` **Descriere:** Combinația `allow_origins=["*"]` + `allow_credentials=True` este **invalidă conform specificației CORS** (RFC). Browserele moderne o resping. Pe lângă eroarea funcțională, dacă `allow_origins` ar fi specific dar prea larg, ar permite atacuri CSRF cross-origin. **Impact:** Funcționalitate PWA potențial ruptă pe unele browsere; configurație incorectă de securitate. **Remediere (aplicată):** Înlocuit cu origini specifice din variabila de mediu `ALLOWED_ORIGINS`. --- ### [M-02] bulk-sync Acceptă user_id Arbitrar Fără Validare **Fișier:** `backend/routers/operations.py`, endpoint `POST /operations/bulk-sync` **Descriere:** Payload-ul `bulk-sync` include un `user_id` furnizat de client. Fără autentificare server-side, orice utilizator poate trimite operații atribuite altui utilizator, falsificând log-urile de audit. **Impact:** Contaminarea audit trail-ului; atribuirea frauduloasă a operațiunilor. **Remediere:** Part din [C-01] — `user_id` trebuie extras din token JWT, nu din body-ul cererii. --- ### [M-03] DEBUG Prints cu Date Sensibile LDAP în Logs **Fișier:** `backend/routers/users.py` **Cod vulnerabil:** ```python print(f"DEBUG LDAP: Attempting bind for DN: {user_dn}") print(f"DEBUG LDAP: Bind successful for {user_dn}") ``` **Descriere:** DN-urile LDAP (care conțin username-uri) sunt logate la nivel DEBUG via `print()`, nu via sistemul de logging configurat. Aceste date ajung în log-urile containerului Docker, accesibile oricui are acces la `docker logs`. **Impact:** Expunerea structurii directorului LDAP și a username-urilor. **Remediere (aplicată):** Înlocuit `print()` cu `log.debug()` și nivel configurable. --- ## 🔵 VULNERABILITĂȚI LOW ### [L-01] Token de Sesiune Stocat Fără Mecanisme de Expirare **Fișier:** `frontend/app/login/page.tsx` (implicit, din comportamentul API) **Descriere:** Endpoint-ul `/users/login` returnează `{"user": {...}, "role": "..."}` fără niciun JWT token cu expirare. Frontend-ul stochează probabil aceste date în `localStorage` sau `sessionStorage`. Fără token de expirare, o sesiune furată este permanent validă. **Impact:** Hijacking de sesiune persistent. **Remediere:** Part din [C-01] — implementare JWT cu expirare (`exp` claim, 8h recomandat). --- ## ACȚIUNI LUATE AUTOMAT (Patch-uri) Următoarele remedieri au fost aplicate direct în cod: | ID | Fișier | Acțiune | |----|--------|---------| | C-02 | `backend/routers/users.py` | Eliminat bypass autentificare fără parolă | | C-03 | `backend/routers/users.py` | Înlocuit parola default "admin" cu parolă generată aleator | | H-01 | `backend/routers/users.py` | LDAP injection fix cu `escape_filter_chars` | | H-03 | `backend/routers/items.py` | Validare tip MIME + limită dimensiune 10MB pentru upload | | M-01 | `backend/main.py` | CORS fix cu origini specifice din env | | M-03 | `backend/routers/users.py` | Înlocuit `print()` cu `log.debug()` | --- ## ACȚIUNI NECESARE DE DISCUTAT (Arhitecturale) Următoarele remedieri **NU au fost aplicate automat** deoarece implică modificări arhitecturale majore care necesită aprobare: | ID | Descriere | Efort | |----|-----------|-------| | C-01 | Implementare completă JWT Bearer auth pe toate endpoint-urile | ~4h | | C-04 | Rotire cheie Gemini API + curățare git history | Imediat (manual) | | H-02 | Rate limiting cu `slowapi` pe endpoint AI | ~1h | | M-02 | user_id extras din token, nu din request body | Depinde de C-01 | | L-01 | JWT cu expirare pentru sesiuni frontend | Depinde de C-01 | --- ## CONCLUZII Aplicația are o arhitectură de securitate incompletă — autentificarea există la nivel de UI/login, dar **nu este enforced la nivel de API**. Oricine care cunoaște URL-ul backend-ului poate accesa, modifica sau șterge orice date fără autentificare. **Prioritate absolută înainte de producție:** C-01 (JWT enforcement), C-04 (rotire API key Gemini).