Skip to content

Security: GOATnote-Inc/medomni

Security

SECURITY.md

Security Policy

Reporting a vulnerability

If you discover a security vulnerability in MedOmni, do not open a public issue.

Email security@thegoatnote.com with:

  • A description of the vulnerability
  • Steps to reproduce
  • Affected versions / components
  • Suggested mitigation if you have one

We will acknowledge receipt within 72 hours and aim to provide a fix or remediation plan within 14 days for high-severity issues.

Scope

In scope:

  • The MedOmni codebase under this repository
  • The reproducibility manifest emitter (scripts/emit_manifest.py)
  • The pre-commit and CI gates (.pre-commit-config.yaml, .github/workflows/)
  • The API-key handling contract (CLAUDE.md §2) — any code path that leaks or commits a cloud LLM API key is in scope as a security defect
  • The persona-tagged-graph schema (findings/research/2026-04-29-medomni-v1-northstar/SPEC.md §5.5)

Out of scope:

  • Vulnerabilities in upstream NVIDIA components (CUDA, RAPIDS, NeMo, TensorRT-LLM, vLLM) — please report those directly to NVIDIA
  • Vulnerabilities in upstream model weights — please report those to Hugging Face / the weight publisher
  • Theoretical attacks against medical-AI systems in general — the LICENSE includes the standard warranty disclaimer; medical decisions remain the responsibility of the credentialed clinician

Supported versions

Version Supported
0.1.x Yes
< 0.1.0 No

Operational security doctrine (durable rules)

These rules are extracted from real incidents in this project and the broader GOATnote stack. They are non-negotiable:

Never read .env value contents directly

Reading .env loads its contents into the conversation context, which exposes secrets to LLM agents and to any logging surface. Use awk to inspect key names only:

awk -F= '/^[A-Z_]+=/ {print $1, "len:", length($2)}' .env

Do not use cat .env, grep -E 'KEY=|TOKEN=|SECRET=' .env, or any pipeline that interpolates the value into a shell variable that gets re-exported.

Never push secrets through SSH proxies that allocate a PTY

The 2026-04-29 incident (full postmortem in the private research repo) leaked an HF_TOKEN through ssh.runpod.io's required PTY allocation. PTYs echo stdin to stdout server-side; the client cannot disable this. Heredoc, base64, inline-env, and stdin-pipe all leak.

The durable mitigation is scripts/_runpod_ssh.sh, which carries a hard secret-grep guard. It refuses to forward any command body matching (API_KEY|SECRET|PASSWORD|TOKEN)= patterns or specific known-secret prefixes (hf_*, nvapi-*, sk-*, sk-ant-*, xai-*, AIza*, ghp_*, ghs_*).

Provision pod secrets via:

  • The pod provider's console environment-variable UI, or
  • A separate user-controlled SSH session that is not under agent control

Never via a Claude-driven shell.

Never commit cloud LLM API key VALUES to any path

Per CLAUDE.md §2, cloud LLM keys are scoped, not forbidden: the demo BFF uses an Anthropic key held only in Vercel project env, eval graders source keys out-of-band on the operator's machine, and CI uses the ANTHROPIC_API_KEY_PR_REVIEW repo secret. (The historical "exactly two secrets / no cloud LLM keys in any code path" contract described the pre-June-2026 self-hosted deployment.)

Key VALUES in the repo — OPENAI_API_KEY=sk-..., ANTHROPIC_API_KEY=sk-ant-..., etc. — are blocked by:

  • The no-cloud-llm-keys.sh pre-commit hook
  • The detect-secrets baseline (Yelp, Apache-2.0; aligns with the NVIDIA-NeMo org convention used by NeMo, NeMo-Run, and NeMo-Curator)
  • TruffleHog OSS in CI — verifier-based scanning that actively calls candidate-secret APIs to confirm a match is a live credential, not just a regex hit (700+ verifiers, ~near-zero false-positive rate in --results=verified mode). Aligns with the NVIDIA core convention used by NVIDIA/bionemo-framework, NVIDIA/Model-Optimizer, and packaged in NVIDIA/dsx-github-actions/.../trufflehog-scan/action.yml. Replaces the previous gitleaks-action step (which moved to a paid-license model in 2025).
  • A grep CI gate on every PR

If you find yourself adding one of those keys to a script or an env-template, the design is wrong. The judge runs locally on H100. The serve runs locally on H200. External keys defeat the entire premise.

Never run secret-printing commands

The 2026-04-27 prism42 incident and the 2026-04-29 medomni incident both involved commands that printed env-var contents to a shell that was being captured by a logging surface. Do not run:

  • systemctl show ... --property=Environment
  • cat /proc/*/environ
  • bare printenv or env (without filter)
  • cat .env
  • grep -E 'KEY=|TOKEN=|SECRET=' over a file containing values

Use the awk pattern above to read key names without values.

Pre-commit must pass clean

No --no-verify. If a pre-commit hook fails, fix the underlying issue and create a new commit — not --amend. After a hook failure, the commit did not happen, so --amend would modify the previous commit (potentially losing work).

Branch protection holds

Required status checks: lint, test, manifest-verify, secrets-scan. No force-push to main. No deletions. enforce_admins=false allows admin bypass for solo-dev sprints; this is intentional and reviewed quarterly.

Threat model

MedOmni is a clinical decision-support codebase. Its threat model is shaped by:

  1. Hallucinated medical content — addressed by the constrained-decoding cite rail (SPEC §5.3 stage 9) and the output-rail Nemotron-Content-Safety-Reasoning-4B with clinical policy.
  2. PHI leak — the demo forbids PHI entry (persistent banner) because the current architecture sends queries to the Anthropic Claude API; the historical self-hosted deployment kept inference on-pod. Do not represent the demo as PHI-safe.
  3. Adversarial jailbreak — addressed by the input-rail NemoGuard JailbreakDetect.
  4. Methodology-side circularity — addressed by held-out fixtures with non-overlapping evidence base, cross-family judge, and N≥3 seeded trials with deterministic decoding.
  5. Supply-chain compromise — addressed by revision-pinned weights in the 9-layer manifest, detect-secrets + TruffleHog OSS dual-layer secret scanning (regex/entropy + verifier-based, both NVIDIA OSS conventions), and pinned dependency versions in pyproject.toml + uv.lock.

Disclosure timeline

We follow standard 90-day coordinated disclosure. After acknowledgment:

  • Day 0–14: triage + assignment
  • Day 14–60: fix development + testing
  • Day 60–90: coordinated release
  • Day 90+: public disclosure (with credit to the reporter, if they wish)

There aren't any published security advisories