Appearance
Keryx QR and ntfy threat model
Reviewed: 25 August 2026
This document is the P1-01 threat model for SafeCall administrator QR provisioning and ntfy topic access used by Keryx for SafeCall. It records how the current implementation behaves, which abuse cases matter for a public launch, and which GitLab work items own the treatments.
It does not claim that production is secure, that TLS or credentials are already enforced, or that a penetration test was performed. Protocol design belongs to P1-02/#95.
Purpose and non-goals
Purpose
- Map trust boundaries, assets, actors, and data flows for the admin-to-device notification path.
- Rate launch-relevant abuse cases and assign treatments and owners.
- Give #95 and related P1 items an evidence-based control agenda.
Non-goals
- Implementing HTTPS enforcement, ntfy credentials, or a new QR schema.
- Changing SafeCall publish code, Keryx storage, or production ntfy servers.
- Approving HTTP for production, accepting anonymous topics, or waiving launch-blocker controls.
- Replacing the separate privacy, Data Safety, or safety-claims workstreams.
System context
mermaid
flowchart LR
Admin[SafeCall_admin_UI]
QR[QR_payload_v1]
Keryx[Keryx_device]
Ntfy[ntfy_server]
Publisher[SafeCall_publisher]
Admin -->|"generates"| QR
QR -->|"scan stores config"| Keryx
Keryx -->|"subscribe stream poll"| Ntfy
Publisher -->|"POST alerts"| Ntfy
Ntfy -->|"messages"| KeryxTrust boundaries:
| Boundary | What crosses it | Current control |
|---|---|---|
| SafeCall admin session | Authenticated admin selects categories and generates QR | SafeCall JWT/admin guard; QR itself is not authenticated to ntfy |
| Optical / shared QR channel | JSON payload leaves the admin browser | Anyone who can see or copy the QR obtains the same subscribe capability |
| Device storage | Config and alert history on the phone/tablet | SharedPreferences; no remote wipe or ntfy credential to revoke |
| Network path to ntfy | Subscribe, poll, and publish HTTP(S) | Keryx accepts http and https; SafeCall publish has no Authorization header in source |
| ntfy host | Topic namespace and message cache | Topic names are {server_id}-{topic_id}; host operator can read traffic and cache |
Assets
| Asset | Sensitivity | Where it appears today |
|---|---|---|
| Topic names | High — knowledge enables subscribe/publish on open servers | QR, device config, debug UI, SafeCall topic list |
| Alert bodies | High — may include device names, MACs, operational or location-like content | ntfy messages, Keryx Active/Archive, OS notification UI, SharedPreferences |
| QR payload | High — server URL, topics, labels, optional debug flag | Admin canvas, screenshots, printed/shared images |
| Local config | High — durable subscribe capability on device | KeryxConfigStore SharedPreferences |
| Local notification history | High — retained message and raw JSON | NotificationStore SharedPreferences |
| Publish capability | Critical — ability to inject false or nuisance alerts | Anyone who can POST to an unprotected topic |
| Debug metadata | Medium–High — topics and raw message fields | Detail UI when debug_access is true |
Actors
| Actor | Intent | Capabilities assumed |
|---|---|---|
| SafeCall administrator | Legitimate provisioning and use | Generates QR, scans on own device, pauses/resets/rescans |
| Contracted client IT | Device and network policy | MDM install channel only; no managed config injection at launch |
| Attacker with QR disclosure | Obtain subscribe (and often publish) access | Photos, screen shares, printed QR, support ticket attachments |
| Attacker who guesses topics | Enumerate {server_id}-* topics | Knowledge or leak of server_id / naming pattern |
| Malicious publisher | Spoof or spam alerts | Unauthenticated POST to open topics |
| Holder of lost/stolen device | Continue receiving alerts; read history | Physical device with stored config until reset/uninstall |
| Support / debug operator | Diagnose delivery | May enable debug_access and see transport details |
| ntfy host operator | Operate infrastructure | Full host and cache access; must be treated as a processor/trust party |
Data flows
- QR generation — Admin UI reads configured
ntfy_server_urland selected topics/labels, optionally setsdebug_access, encodessafecall.keryx.ntfy.v1JSON, renders a QR canvas. - QR scan — Keryx parses the payload, accepts
httporhttps, stores config locally, starts native subscription / HTTP poll recovery. - SafeCall publish — Server posts alert text to topic URLs via curl transport without an Authorization header in the current source path.
- Receive and retain — Messages enter Active/Archive; content can appear in OS notifications; history and raw JSON persist on device.
- Rescan / reset — Local config can be replaced or cleared on the device; there is no separate ntfy credential to revoke on the server.
- Offboarding gap — An ex-administrator device that still holds config can keep subscribing until the app is reset/uninstalled or topics become unreachable; current design has no per-device revocation handle.
Abuse cases
Likelihood and impact are relative to a Czech public-store launch for contracted SafeCall administrators. Residual risk assumes current code unless a treatment is closed.
A1 — QR disclosure
- Description: An attacker obtains a photo, screenshot, printed QR, or shared image of a provisioning QR.
- Likelihood: Medium–High (ops reality of screen sharing and paper QRs).
- Impact: High — same subscribe set as the administrator; often publish if topics are open.
- Residual risk: Launch blocker until least-privilege credentials and revocation exist.
- Treatment: #95 (credentials in QR, rotation/revocation); admin guidance in #120/#121 (do not leave durable QRs unattended).
A2 — Topic guessing / enumeration
- Description: Attacker derives
{server_id}-{topic_id}from a known or leaked server ID and the fixed topic id list. - Likelihood: Medium when
server_idvalues are short, shared, or visible in other SafeCall surfaces. - Impact: High on open servers — subscribe and publish without a QR.
- Residual risk: Launch blocker while topics are unauthenticated and predictable.
- Treatment: #95 (authz boundary replaces topic secrecy); #119 (client ntfy hardening prerequisites).
A3 — Unauthorized subscribe
- Description: Third party listens to operational alerts without being an authorized administrator.
- Likelihood: High while anonymous subscribe works.
- Impact: High — confidentiality of building/ops alerts.
- Residual risk: Launch blocker.
- Treatment: #95 subscribe credentials; #98/#99 disclosures must match actual residual exposure until controls land.
A4 — Unauthorized publish
- Description: Attacker posts forged panic, sensor, or health alerts.
- Likelihood: High on open publish.
- Impact: Critical — false emergency signal and trust collapse; still not a regulated medical device, but operational harm is real.
- Residual risk: Launch blocker.
- Treatment: #95 separate publish credentials and rate/abuse controls; #103 honest safety/limitation claims; #119 deployer checklist.
A5 — HTTP downgrade / network MITM
- Description: Keryx accepts
http://ntfy URLs; a network attacker can observe or modify subscribe/poll traffic, or an admin can provision cleartext by mistake. - Likelihood: Medium (depends on client network and configured URL).
- Impact: High — credential and alert interception once auth exists; today, cleartext alert content and topic names.
- Residual risk: Launch blocker for production; private-network HTTP only if #95 records an explicit exception.
- Treatment: #95 TLS-only default with any exception decided in writing.
A6 — Spoofed or replayed messages
- Description: Without authenticated publish and with cache/poll recovery, an attacker may inject or re-deliver messages that look legitimate in-app.
- Likelihood: Medium–High on open topics; replay depends on cache and client dedupe.
- Impact: High — false alerts and operator confusion.
- Residual risk: Launch blocker for injection; replay residual handled with #95 plus app dedupe evidence in P4.
- Treatment: #95 publish auth; keep client dedupe; document cache limits in #103/#119.
A7 — Device loss without remote revocation
- Description: Lost or stolen phone retains config and history; subscriptions continue until local reset/uninstall.
- Likelihood: Medium.
- Impact: High — continued alert confidentiality breach.
- Residual risk: Launch blocker until revocation exists; interim compensating control is topic credential rotation after loss reports.
- Treatment: #95 revocation/rotation; #98 device-loss and offboarding controls; #120/#121 replacement/offboarding steps.
A8 — Debug access overexposure
- Description: Admin enables
debug_accessin the QR; detail UI shows topics and raw message metadata beyond the normal administrator journey. - Likelihood: Medium during support.
- Impact: Medium–High if screenshots or shoulder-surfing expose transport details.
- Residual risk: Accepted only with restricted use and guidance; not a substitute for #95.
- Treatment: Keep debug off by default; #120/#121 restrict debug to support; #98 diagnostic redaction.
A9 — Logging and diagnostics leakage
- Description: Support tickets, device logs, or future telemetry include topics or alert bodies.
- Likelihood: Medium if operators paste debug screens.
- Impact: Medium–High.
- Residual risk: Managed by process until #132 intake redaction and #99 policy text are live; classification and redaction rules are approved in data-classification.md. P0-05 already forbids analytics/crash SDKs at launch.
- Treatment: #98 diagnostic redaction (approved); #99 policy text; #132 intake rules; no new collection before privacy approval.
A10 — Offboarding failure
- Description: Former administrator keeps a provisioned device; no server credential to invalidate.
- Likelihood: Medium in staff-turnover scenarios.
- Impact: High — indefinite subscribe on open topics.
- Residual risk: Launch blocker without revocation; process-only offboarding is insufficient as the sole control.
- Treatment: #95 revocation; #120/#121 offboarding; client runbooks via #119.
Risk rating summary
| ID | Abuse case | Rating | Launch posture |
|---|---|---|---|
| A1 | QR disclosure | High | Launch blocker — treat with #95 |
| A2 | Topic guessing | High | Launch blocker — treat with #95/#119 |
| A3 | Unauthorized subscribe | High | Launch blocker — treat with #95 |
| A4 | Unauthorized publish | Critical | Launch blocker — treat with #95/#103/#119 |
| A5 | HTTP / MITM | High | Launch blocker — treat with #95 |
| A6 | Spoof / replay | High | Launch blocker — treat with #95; P4 proves dedupe |
| A7 | Device loss | High | Launch blocker — treat with #95/#98 |
| A8 | Debug overexposure | Medium | Compensating guidance; not a #95 substitute |
| A9 | Log leakage | Medium | Process + #98/#99/#132 |
| A10 | Offboarding failure | High | Launch blocker — treat with #95/#120/#121 |
No anonymous or cleartext production design is accepted by default. Closing this threat model does not accept residual A1–A7/A10 risk; those remain open until their treatment issues close or the go/no-go authority records a dated acceptance in the roadmap.
Required treatments
| Control theme | Owning work item |
|---|---|
| HTTPS enforcement, subscribe/publish credentials, QR versioning, rotation, revocation, legacy v1 migration | #95 — protocol approved in provisioning-protocol.md; implementation still open |
| Local data classification, retention, lock-screen, device loss, diagnostic redaction | #98 — policy approved in data-classification.md; SharedPreferences + full lock-screen for launch; privacy/forms and revoke UX remain open |
| Privacy, terms, support commitments matching real flows | #99 |
| Apple privacy / encryption / SDK disclosures | #100 |
| Play Data Safety and related declarations | #101 |
| Safety claims and delivery limitations | #103 packet: safety-claims.md |
| Client ntfy/TLS/auth/push prerequisites for deployers | #119 |
| Administrator provisioning, replacement, offboarding guidance | #120, #121 |
Review record
- Status: approved as the P1-01 threat model.
- Date: 25 August 2026.
- Reviewer: Thomas Minitsios, covering product, mobile, server, ops, and privacy roles under the P0-05 RACI. The single-person concentration risk remains named; reopen review if a second named reviewer becomes available.
- Evidence sources:
keryx/lib/models/keryx_config.dart,keryx/lib/services/keryx_config_store.dart,keryx/lib/services/notification_store.dart,web/src/admin/tools/mobile-access/mobile-access.ts,server/src/ntfy_topics.ts,server/src/ntfy.ts,docs/gtm/keryx/roadmap.md. - Next step: #95 protocol is approved in provisioning-protocol.md. Implementation of HTTPS enforcement, tokens, and QR v2 remains open and must not weaken the administrator-only SafeCall companion product model.