Skip to content

Threat model

MedAgentRx reads files that people and agents control, and its verdict decides whether a clinical model update may be released. This page lists what it defends against, using STRIDE: spoofing, tampering, repudiation, information disclosure, denial of service and elevation of privilege.

Assets

  • The verdict and the decision it supports.
  • The decision ledger, which holds the plan's budgets: test-set looks, alpha and accepted updates.
  • The locked test set, whose value depends on limited use.
  • The reader of reports and the dashboard.

Threats and mitigations

Threat STRIDE Mitigation Where
Malicious plan file runs code through YAML tags Elevation of privilege Hardened SafeLoader: no Python tags, no aliases, no duplicate keys; JSON Schema and pydantic validation with unknown keys refused safe_yaml.py, plan/
Plan file exhausts memory (billion laughs, huge file, deep nesting) Denial of service Anchors and aliases refused; byte limit before parsing; nesting depth caught safe_yaml.py, io/text.py
Malicious prediction or model file runs code when loaded Elevation of privilege Predictions only, as CSV or Parquet; model binaries, pickles and joblib files are never opened; no eval or exec io/
Oversized or malformed prediction file Denial of service Byte and row limits checked before reading (Parquet from its footer); nested types, NaN, out-of-range scores and duplicate ids refused io/tables.py, io/predictions.py
Symlink in a checkout points at secrets outside it Information disclosure Inside the working directory, symlinks are followed only when they stay inside it io/paths.py
Output written outside the output folder Tampering Output names checked; absolute paths, .. and symlinked targets refused io/paths.py
Script injection through plan text, labels or data into reports Tampering, information disclosure Jinja2 autoescaping; no script in reports; figures drawn as paths with no external reference; CSP that forbids loading anything report/
Edited, reordered or removed ledger entries hide failed attempts Tampering, repudiation Hash chain over every entry, a head file and an optional Ed25519 signature on the head, pinned by the plan; check refuses a ledger that fails verification. A trusted copy of the latest head detects rollback ledger.py, signing.py
Two evaluations race for the last test-set look Tampering A lock spans reading budgets to appending; stale evaluations refused ledger.py
Clock set back to slip past the frequency limit Tampering Entries must not run backwards in time; check refuses an earlier time and verify reports one ledger.py
An agent fits the locked test set by trying many candidates Information disclosure Look budget counts every try; thresholdout mode returns one noisy bit; only automatic modifications allowed guard.py
Changed test labels or a different test set Tampering Canonical test-set fingerprint pinned in the plan (DATA-001) io/fingerprint.py
Plan changed without a new revision Tampering, repudiation Plan fingerprint recorded in the ledger and compared (PLAN-001) checks/plan_checks.py
Dashboard exposed to a network Information disclosure Read-only GET routes, no cookies, strict security headers; binds to 127.0.0.1 and warns loudly otherwise web/
Compromised dependency or image Tampering Locked dependencies; pip-audit, CodeQL, Trivy and OpenSSF Scorecard in CI; base images pinned by digest; image signed and shipped with an SBOM and provenance CI, Dockerfile

Residual risks

  • Without a signing key, whoever controls both the ledger and its head file can rewrite history. Pin a signing key in the plan, or keep a copy of the head where the ledger's writers cannot change it.
  • A clock set forward is not detected when it happens. Later entries made with the correct time are then refused, which shows the problem, but the frequency limit was already measured from the wrong time. Run checks on a host with a trusted, synchronised clock.
  • A signed head does not prevent rollback. Truncating the ledger and restoring an older signed head passes verification unless the verifier holds a newer head. Keep the latest head outside the writers' reach, or anchor it in a transparency log (see the roadmap).
  • Whoever holds the signing key can sign a rewritten head. Keep the key with a party that does not train or submit models, such as a protected CI secret.
  • The tool trusts that prediction files come from the models they claim to. Model provenance is the quality system's job.
  • In thresholdout mode each look still leaks a little information. The look budget bounds the total.