9.6 KiB
Code Review TODO — Clearview
Aangemaakt: 2026-05-19
Branch bij review: refactor/scanner-package-frontend
Scope: Eerste volledige review (~7.100 regels code)
Totaal: 13 CRITICAL · 19 HIGH · 14 MEDIUM · 1 LOW
Werkvolgorde: alle CRITICAL eerst (P0), daarna HIGH (P1), dan MEDIUM/LOW (P2). Per item staan severity, bestand(en):regel(s), en de gewenste fix.
P0 — CRITICAL (eerst dichten)
Auth & secrets
-
Geen authenticatie op enig API-endpoint
containers/clearview/src/clearview_app/main.py(alle/api/routes)- Fix: API-key via
X-API-Keyheader met FastAPISecurity()dependency, of Bearer-token op alle/api/routes.
-
Client secrets staan plaintext in DB
containers/clearview/src/clearview_app/models.py:21(TenantProfile.client_secret)containers/clearview/src/clearview_app/models.py:45(ScanJob.auth_client_secret)- Fix: encrypt-at-rest met
cryptography.fernet; key via env var. Decrypt enkel in geheugen bij gebruik.
-
.envniet in.gitignore.gitignore,stack/.env- Fix: voeg
stack/.enven**/.envtoe aan.gitignore; leverstack/.env.examplemet placeholders; verifieer dat.envnog niet in git history zit (anders rotate credentials).
-
Hardcoded DB-fallback
clearview:clearviewcontainers/clearview/src/clearview_app/config.py:17-19- Fix: verwijder default;
raise RuntimeError("DATABASE_URL required")als env ontbreekt.
-
Adminer publiek op
0.0.0.0:8081stack/docker-compose.yml:44-46- Fix: bind aan
127.0.0.1:${ADMINER_PORT:-8081}:8080of verwijder uit prod-compose.
Injectie & exfiltratie
-
XSS via ongescapete velden in
innerHTML(3 vindplaatsen)containers/clearview/site/app.js:658-676(job.id,job.source_type,job.items_scanned)containers/clearview/site/app.js:885-894(job.status,total/processed/successful/failed_targets,items_scanned)containers/clearview/site/app.js:175-184(statusBadge()zonder escape opstatus)- Fix: consequent
escHtml()op alle API-velden, óók ID's en numerieke. Geen uitzonderingen.
-
Open redirect via
payload.connect_urlcontainers/clearview/site/app.js:472- Fix: valideer
new URL(payload.connect_url).protocol === 'https:'+ host-allowlist (login.microsoftonline.com).
-
SSRF / token-exfiltratie via
@odata.nextLinkcontainers/clearview/src/clearview_app/scanners/sharepoint.py:547-553containers/clearview/src/clearview_app/scanners/entra.py:227-272- Fix: vergelijk
urlparse(next_url).netloc == urlparse(original_url).netloc; gooi anders eenRuntimeError.
-
Header injection in
Content-Dispositioncontainers/clearview/src/clearview_app/main.py:701-705- Fix: type de route-parameter als
uuid.UUIDzodat FastAPIjob_idvalideert;urllib.parse.quote(filename, safe="").
P1 — HIGH
Correctheid
-
Token cache zonder TTL — workers crashen na 1 uur
containers/clearview/src/clearview_app/scanners/sharepoint.py:34, 512-543- Fix: bewaar
expires_at = time.time() + result["expires_in"] - 60; invalideer in_get_token_for_host.
-
MSAL
ConfidentialClientApplicationper aanroepcontainers/clearview/src/clearview_app/scanners/sharepoint.py:530- Fix: module-level dict
(tenant_id, client_id, auth_method) -> app. Hergebruik object.
-
_TOKEN_CACHEzonder lock (race in multi-thread)containers/clearview/src/clearview_app/scanners/sharepoint.py:34- Fix:
threading.Lockrond check-then-write, offunctools.lru_cache+ TTL-wrapper.
-
Race condition in worker: niet-atomaire job-claim
containers/clearview/src/clearview_app/worker.py:48-68- Fix: één
UPDATE scan_jobs SET status='running' WHERE id=:id AND status='queued' RETURNING idmetFOR UPDATE SKIP LOCKED.
-
Auto-refresh race in frontend
containers/clearview/site/app.js:1009-1013+ alletick()callsites- Fix:
AbortControllerper render; vorige request cancelen voordat nieuwe gestart wordt.
-
Event-listener accumulatie / re-render-pattern
containers/clearview/site/app.js:238-270, 678-702- Fix: event delegation op stabiele container (
els.jobsTableBody.addEventListener('click', ...)).
-
Sequentieel awaiten van onafhankelijke calls
containers/clearview/site/app.js:554-555, 999, 1281, 1364- Fix:
await Promise.all([refreshJobs(), refreshSelectedJob()]).
-
Niet-afgehandelde floating promise
containers/clearview/site/app.js:1143- Fix:
.catch(err => showFeedback(...))optestTargetConnection(...).
-
OAuth state-store is in-memory dict (breekt bij
--workers >1)containers/clearview/src/clearview_app/onboarding.py:31, 134-145- Fix: state opslaan in DB (tabel
oauth_statesmetcreated_at,consumed_at) of Redis.
-
scan_typeongevalideerdcontainers/clearview/src/clearview_app/schemas.py:36,main.py:178, 207- Fix:
Literal["sharepoint","sharepoint_root","mailbox","entra_groups"]in Pydantic schema.
-
datetime.utcnow()deprecated, timezone-naive (overal)main.py,worker.py,models.py:26-27,cert.py:33- Fix:
datetime.now(timezone.utc);DateTime(timezone=True)in SQLAlchemy-kolommen.
-
ThreadPoolExecutor(max_workers=1)per targetcontainers/clearview/src/clearview_app/worker.py:307- Fix: gedeelde executor; documenteer dat
future.cancel()lopende scan niet onderbreekt.
-
Geen throttling-respect bij 429 in item-loop
containers/clearview/src/clearview_app/scanners/sharepoint.py:603-619- Fix: batching via
$expand=RoleAssignmentsof exponential backoff op item-niveau.
Hardening
-
Container draait als root
containers/clearview/Dockerfile- Fix:
RUN adduser --system --ingroup clearview clearview+USER clearview.
-
.debvan packages.microsoft.com zonder checksumcontainers/clearview/Dockerfile:17-19- Fix: hardcoded SHA256 +
sha256sum --check, of officiële GPG-key viasigned-by.
-
Install-Module ExchangeOnlineManagementzonder versie-pincontainers/clearview/Dockerfile:24-26- Fix:
-RequiredVersion 3.7.0(of huidige geteste versie).
-
Graph-foutberichten gelekt richting frontend
containers/clearview/src/clearview_app/onboarding.py:170, 188- Fix: volledig log naar server-side DEBUG; aan client alleen generieke code + HTTP-status.
-
OData-filter injection via displayName/mail
containers/clearview/src/clearview_app/scanners/entra.py:178-196- Fix:
urllib.parse.quote(cleaned.replace("'", "''"), safe="").
-
PowerShell-args zonder UPN-validatie
containers/clearview/src/clearview_app/scanners/mailbox.py:181-190containers/clearview/src/clearview_app/scanners/exo_scripts/get-permissions.ps1:107- Fix:
re.fullmatch(r"[^@\s]{1,64}@[^@\s]{1,255}", upn)vóór_run_pwsh.
Architectuur
-
main.pyis 1139 regels — splitsen- Fix:
routers/{tenants,jobs,onboarding}.py,services/job_service.py,export.py.
- Fix:
-
sharepoint.pyis 722 regels — splitsen- Fix:
_auth.py,_http.py,sharepoint.py(publieke scanfuncties),sharing_links.py.
- Fix:
-
_ensure_schema_columns()met 18 rawALTER TABLEcontainers/clearview/src/clearview_app/main.py:1115-1139- Fix: vervang door Alembic; commit baseline-migratie + history.
P2 — MEDIUM / LOW
app.js1586 regels, geen build step — splits in ES-modules + esbuild/rollup; verwijder IIFE-wrapper.- Focus management bij route-wissel ontbreekt —
app.js:1529-1551— focus naar<h2>van nieuwe route na navigatie. - Focus-outline 38% opacity voldoet niet aan WCAG 3:1 —
styles.css:292-296—outline: 2px solid var(--cv-accent). - Geen debouncing/abort op
jobSiteFilter—app.js:1158-1172—AbortControllerper fetch. els.submitFeedbackgebruikt voor niet-SharePoint feedback —app.js:682, 711— generiek feedback-element of context-specifiek.- Magic string
'__manual__'—app.js:412, 424— named constant. - Icon-knoppen missen
aria-label—app.js:229-231—aria-labeltoevoegen. scanner.pyis shim zonder waarschuwing —DeprecationWarningof verwijderen.except Exception: passzonder logging (meerdere) — minimaallog.warning(..., exc_info=True)._resolve_credentials(db, ...)mist type-hint —main.py:935—db: Session.CreateScanAppResponselekt secret zonder waarschuwing —schemas.py:149-155—show_once: boolveld + log-suppression voor dit endpoint.- Deviations hard-capped op 1000 —
main.py:728— voegtotal_deviations_count+truncated: booltoe. - Geen
loggingin scanners-package —import logging; logger = logging.getLogger(__name__)overal. list-mailboxes.ps1laadt alles in geheugen —-ResultSize Unlimited→ paginering of cap.cert.pyprivate key zonder encryptie — documenteer aanname dat caller encryptie-at-rest doet.build-and-push.shdoetgit add -A—build-and-push.sh:294— expliciete file-lijst of bevestigingsprompt.- README build-instructies kloppen niet (1/2/3 vs t/r) —
README.md:80-84.
Werkwijze
- Werk per checkbox; verwijder geen items maar zet
[x]als done. - Bij oplevering van een batch: append entry in
docs/changelog-develop.md. - CRITICAL items vereisen handmatige verificatie (auth-tests, secret-rotation, XSS-payload checks).
- Na P0 + P1: hertest met deze TODO als checklist voordat een nieuwe review wordt aangevraagd.