DENEME BLOg yazısı
asdasd

RCCKM Workstream 2 — Security Review & Hospital Network Compatibility
Date: 2026-07-03 Scope: Identify obvious security/configuration risks before physicians begin testing — HTTPS/TLS setup, secrets management, environment variables, cookie/session security settings, third-party dependencies and external service calls, an external domain map, and hospital-network allowlist guidance. This is a findings-only review, companion to the separate Workstream 1 (Authentication & Session Persistence) review — no code changes made.
Limitation, stated up front: this review can reduce avoidable issues and document the domains RCCKM itself calls or redirects to. It cannot guarantee access from any specific hospital's network — each institution runs its own firewall, proxy, and DLP policy, and some will block things no vendor review can predict. Treat the allowlist recommendations below as "give this list to each site's IT team before pilot day," not as a guarantee.
One-look summary — for Shereef
Plain-English read: what's risky, how bad, and what it means for the pilot.
# | Area | Finding | Severity | What it means in practice |
|---|---|---|---|---|
15 | Cookie/session | No security headers set at all (no CSP, no HSTS, no X-Frame-Options) | Medium | The app has no extra browser-level protection layer if something else goes wrong — a "seatbelt" that's currently missing |
16 | Secrets management | Dependency versions for anthropic, supabase, Authlib, extra-streamlit-components are "at least this version" (>=), not pinned exactly | Medium | A routine pip install can silently pull in a newer, untested version of a security-relevant library right before or during the pilot |
17 | External identity provider | Login redirects to a shared Auth0 "dev" tenant address (dev-5jj8pwjsnv5der0x.us.auth0.com) instead of a RCCKM-branded address | Medium | Some hospital security tools flag generic identity-provider domains as suspicious; it also looks less trustworthy to a physician mid-login on a hospital computer |
18 | Third-party calls | One analytics call (Copy/Print button clicks) runs in the browser and calls PostHog directly; everything else runs from our own server | Low | If a hospital blocks PostHog, physicians can still fully use the app — we just lose click-level usage data for those buttons |
19 | Third-party calls | The marketing landing page loads Google Fonts from Google's servers | Low | If blocked, the landing page still works, just with a plainer font |
20 | Real-time connection | The clinical app itself depends on a persistent live connection (WebSocket) to the server, on top of normal HTTPS | High | This is the single most common reason a Streamlit-style app "freezes" or shows a disconnected/reconnecting banner on hospital Wi-Fi/VPN — independent of login |
21 | CI / process | The automated test suite that runs on every code change does not include the 71 authentication tests | Medium | A future code change could break login and still pass all automated checks before reaching physicians |
22 | Secrets management | API keys (Anthropic, PostHog) are handled well: masked in diagnostics, never logged in full, gated behind explicit debug flags | — (positive) | Nothing to fix here — flagging as confirmed-good so it isn't re-litigated later |
Detailed write-ups for each numbered item are below, grouped by the review categories from the engagement brief, followed by the external domain map, hospital allowlist table, and longer-term hardening ideas.
A. HTTPS / TLS
RCCKM does not terminate TLS itself — Render (the hosting provider) issues and renews the certificate and handles the HTTPS connection at its edge for both app.riskcontinuum.health and the onrender.com fallback; the app receives plain HTTP internally from Render's proxy. This is a standard, reasonable setup and not a finding on its own, but two things should be explicitly confirmed rather than assumed before pilot day:
That Render's automatic "redirect HTTP to HTTPS" is actually turned on for the custom domain (it's on by default for Render web services, but custom domains are where this most often gets missed during DNS setup).
That the custom domain's TLS certificate is valid, auto-renewing, and covers exactly app.riskcontinuum.health (a certificate mismatch is a common, very visible "your connection is not private" browser warning that would immediately erode a physician's trust in the tool).
No code change is needed for either — both are one-time checks in the Render dashboard.
B. Secrets management
(#22, positive) Anthropic API key handling is a good example of the right pattern already in use: renderers/claude_layer.py:243-266 only ever logs a masked form (sk-abc1234...wxyz), gates even that behind an explicit RCCKM_SHOW_INDEPENDENT_REVIEW_DIAGNOSTIC flag, and error logging records only a boolean api_key_present, never the key itself. Worth calling out so it's preserved, not accidentally "simplified away" in a future change.
(#16, Medium) requirements.txt pins streamlit, pandas, numpy, plotly, and pytest to exact versions, but anthropic, supabase, python-dotenv, extra-streamlit-components, and Authlib are all floating (>=). Every one of those last five is security- or auth-relevant. A plain pip install -r requirements.txt at any point (a fresh Render build, a redeploy, a new contractor's laptop) can silently install a newer version than what was tested — best case a behavior change, worst case a regression introduced right before or during physician testing.
No secrets or PHI found committed to the repo. This matches the existing audit in docs/security_privacy_notes.md; this review did not find anything to add to that finding — .env, .streamlit/secrets.toml, and key/cert file patterns are all correctly gitignored, and a repo-wide scan for credential-shaped strings turned up nothing live.
C. Environment variables
Auth mode is currently resolved through an implicit chain of env vars rather than one explicit, fail-loud switch. That's as much a secrets/config-hygiene issue as an auth issue; full detail and remediation steps are in the companion Workstream 1 review (see Findings 1 and 7 there).
One addition specific to this review: ANTHROPIC_API_KEY, SUPABASE_URL, and SUPABASE_ANON_KEY are the only three keys covered by the built-in env-presence diagnostic (ui/env_config.py:17). POSTHOG_API_KEY, AUTH0_CLIENT_ID/AUTH0_CLIENT_SECRET, and the various RCCKM_* cookie/domain overrides have no equivalent "is this configured" startup check — if one of those is missing or mistyped, the failure mode is silent (a feature just quietly doesn't work) rather than a clear startup diagnostic line.
D. Cookie / session security settings
Full detail on the items below is in the companion Workstream 1 review (Findings 2, 3, 6, 8); summarized here for completeness against the Workstream 2 checklist:
Supabase-mode session cookies are not HttpOnly.
The Secure cookie attribute is inferred from Render-specific env vars rather than tied to the actual connection.
(#15, Medium, new in this review) No Content-Security-Policy, Strict-Transport-Security, or X-Frame-Options headers are set anywhere in the stack (confirmed by searching the codebase — none are configured). Streamlit does not expose an easy first-party way to set these, and Render's default proxy doesn't add them either. This isn't unusual for a Streamlit app, but it means there's currently no browser-enforced backstop against clickjacking or script-injection scenarios beyond what the application code itself does right.
E. Third-party dependencies and external service calls
RCCKM talks to five external services. The important distinction for hospital compatibility is who makes the call — RCCKM's own server on Render, or the physician's browser — because only browser-side calls can possibly be blocked by a hospital's network:
Service | Called from | What breaks if blocked |
|---|---|---|
Auth0 (login/logout) | Browser (redirect) | Physician cannot sign in at all |
Supabase (legacy password auth + profile storage) | Server only | Nothing visible to the hospital network; not reachable from the browser |
Anthropic (Claude review layer) | Server only | Nothing visible to the hospital network |
PostHog — most events | Server only | Nothing visible to the hospital network |
PostHog — Copy/Print button clicks only | Browser (fetch/sendBeacon, ui/analytics.py:483-491) | Those specific click events aren't recorded; the Copy/Print buttons themselves still work (analytics call is wrapped in a silent catch, ui/analytics.py:490) |
Google Fonts | Browser, landing page only (landing.html:9-10) | Landing page renders with a fallback system font instead |
(#18/#19, Low) Both browser-side calls (PostHog click analytics, Google Fonts) are non-blocking by design — if a hospital blocks either, the app and the clinical workflow keep working. Only the Auth0 redirect and the app's own domain are load-bearing for the browser.
F. External domain map
Full list of external domains RCCKM's code refers to, for handing to a hospital IT team as-is:
Domain | Owner | Purpose | Browser-facing? |
|---|---|---|---|
app.riskcontinuum.health | RCCKM (custom domain via Render) | Primary application | Yes — required |
rcckm-prevent-era.onrender.com | RCCKM (Render-issued fallback) | Backup application access | Yes — required as fallback |
dev-5jj8pwjsnv5der0x.us.auth0.com | Auth0 (shared tenant subdomain) | Login/logout identity provider | Yes — required |
*.supabase.co (project-specific) | Supabase | Legacy password auth + profile storage | No — server-to-server only |
api.anthropic.com (via SDK default) | Anthropic | Claude AI review layer | No — server-to-server only |
us.i.posthog.com | PostHog | Product usage analytics | Mostly server-to-server; browser-facing only for Copy/Print button click events |
fonts.googleapis.com, fonts.gstatic.com | Landing page typography | Yes — landing page only, not the app itself |
G. Hospital firewall / proxy compatibility
(#20, High) The single biggest hospital-network risk isn't a domain at all — it's the connection type. Streamlit apps (including RCCKM) keep a persistent WebSocket connection open between the browser and the server for as long as the app is on screen; this is separate from, and in addition to, normal HTTPS page loads. Many hospital networks route traffic through proxies, deep-packet-inspection firewalls, or VPNs that either block WebSocket upgrades outright or silently kill long-idle connections. When that happens, the symptom is not a login failure — it's the app appearing to "freeze," repeatedly showing a disconnected/reconnecting indicator, or requiring a manual refresh every few minutes even for an already-signed-in user. This is a very plausible independent contributor to the friction the client has already observed, separate from anything in the companion Workstream 1 review, and it cannot be fixed in the app's own code — it's a property of how Streamlit works. The practical mitigation is entirely on the "what do we tell hospital IT" side (see recommendations below), not a code fix.
Recommended hospital allowlist request
What to hand to a pilot site's IT/network security team, in priority order:
Priority | Domain / requirement | Why |
|---|---|---|
Required | app.riskcontinuum.health (HTTPS, port 443, and WebSocket/`wss://` upgrades on the same host) | Primary application; without WebSocket support the app will not function even if the page itself loads |
Required | dev-5jj8pwjsnv5der0x.us.auth0.com (HTTPS, top-level redirect) | Login cannot complete without this |
Recommended fallback | rcckm-prevent-era.onrender.com (same HTTPS + WebSocket requirement as above) | Backup access if the primary domain is ever blocked or has DNS trouble |
Optional | us.i.posthog.com | Only affects Copy/Print click analytics; app fully works without it |
Optional | fonts.googleapis.com, fonts.gstatic.com | Only affects the marketing landing page's typography |
No hospital allowlisting is needed for Supabase or Anthropic — those calls never leave Render's own network.
Future security hardening recommendations (post-pilot)
Not needed to start the 10–15 physician pilot; worth revisiting once the product's usefulness is validated and a larger investment is being considered:
Add security response headers (CSP, HSTS, X-Frame-Options) via a reverse proxy or Render-level configuration in front of Streamlit.
Pin the currently-floating dependencies (anthropic, supabase, python-dotenv, extra-streamlit-components, Authlib) to exact, tested versions, and add a routine (even quarterly, manual) dependency review.
Move off the shared Auth0 "dev" tenant domain to an Auth0 custom domain (e.g. login.riskcontinuum.health) so the login redirect is RCCKM-branded and reads as first-party to both physicians and hospital security tooling.
Add tests/unit (including the auth suite) to the CI workflow in .github/workflows/validation.yml, which currently runs golden-case, invariant, governance, and snapshot tests but not the unit test directory — so the 71 existing auth tests provide no protection against a future change breaking login before it reaches physicians.
Add a startup "configuration presence" diagnostic for the auth-adjacent env vars that don't currently have one (POSTHOG_API_KEY, AUTH0_CLIENT_ID/SECRET, RCCKM_COOKIE_*), matching the pattern already used for Supabase/Anthropic keys.
