Skip to content

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"| Keryx

Trust boundaries:

BoundaryWhat crosses itCurrent control
SafeCall admin sessionAuthenticated admin selects categories and generates QRSafeCall JWT/admin guard; QR itself is not authenticated to ntfy
Optical / shared QR channelJSON payload leaves the admin browserAnyone who can see or copy the QR obtains the same subscribe capability
Device storageConfig and alert history on the phone/tabletSharedPreferences; no remote wipe or ntfy credential to revoke
Network path to ntfySubscribe, poll, and publish HTTP(S)Keryx accepts http and https; SafeCall publish has no Authorization header in source
ntfy hostTopic namespace and message cacheTopic names are {server_id}-{topic_id}; host operator can read traffic and cache

Assets

AssetSensitivityWhere it appears today
Topic namesHigh — knowledge enables subscribe/publish on open serversQR, device config, debug UI, SafeCall topic list
Alert bodiesHigh — may include device names, MACs, operational or location-like contentntfy messages, Keryx Active/Archive, OS notification UI, SharedPreferences
QR payloadHigh — server URL, topics, labels, optional debug flagAdmin canvas, screenshots, printed/shared images
Local configHigh — durable subscribe capability on deviceKeryxConfigStore SharedPreferences
Local notification historyHigh — retained message and raw JSONNotificationStore SharedPreferences
Publish capabilityCritical — ability to inject false or nuisance alertsAnyone who can POST to an unprotected topic
Debug metadataMedium–High — topics and raw message fieldsDetail UI when debug_access is true

Actors

ActorIntentCapabilities assumed
SafeCall administratorLegitimate provisioning and useGenerates QR, scans on own device, pauses/resets/rescans
Contracted client ITDevice and network policyMDM install channel only; no managed config injection at launch
Attacker with QR disclosureObtain subscribe (and often publish) accessPhotos, screen shares, printed QR, support ticket attachments
Attacker who guesses topicsEnumerate {server_id}-* topicsKnowledge or leak of server_id / naming pattern
Malicious publisherSpoof or spam alertsUnauthenticated POST to open topics
Holder of lost/stolen deviceContinue receiving alerts; read historyPhysical device with stored config until reset/uninstall
Support / debug operatorDiagnose deliveryMay enable debug_access and see transport details
ntfy host operatorOperate infrastructureFull host and cache access; must be treated as a processor/trust party

Data flows

  1. QR generation — Admin UI reads configured ntfy_server_url and selected topics/labels, optionally sets debug_access, encodes safecall.keryx.ntfy.v1 JSON, renders a QR canvas.
  2. QR scan — Keryx parses the payload, accepts http or https, stores config locally, starts native subscription / HTTP poll recovery.
  3. SafeCall publish — Server posts alert text to topic URLs via curl transport without an Authorization header in the current source path.
  4. Receive and retain — Messages enter Active/Archive; content can appear in OS notifications; history and raw JSON persist on device.
  5. Rescan / reset — Local config can be replaced or cleared on the device; there is no separate ntfy credential to revoke on the server.
  6. 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_id values 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_access in 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

IDAbuse caseRatingLaunch posture
A1QR disclosureHighLaunch blocker — treat with #95
A2Topic guessingHighLaunch blocker — treat with #95/#119
A3Unauthorized subscribeHighLaunch blocker — treat with #95
A4Unauthorized publishCriticalLaunch blocker — treat with #95/#103/#119
A5HTTP / MITMHighLaunch blocker — treat with #95
A6Spoof / replayHighLaunch blocker — treat with #95; P4 proves dedupe
A7Device lossHighLaunch blocker — treat with #95/#98
A8Debug overexposureMediumCompensating guidance; not a #95 substitute
A9Log leakageMediumProcess + #98/#99/#132
A10Offboarding failureHighLaunch 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 themeOwning 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.