# GrantFlow Threat Model

Honest accounting of what GrantFlow's preflight, generation, critic, HITL, and export pipeline **catches** versus what it does **not** catch.

Companion to:
- [`trust-report.md`](trust-report.md) — what `trust_summary` means and what it does not (output-side trust).
- [`error-contract.md`](error-contract.md) — structured error shape and recovery actions.

`trust-report.md` covers what the **output verdict** means. This document covers the **input and processing surface**: what an adversarial or careless caller can send GrantFlow that downstream consumers should not trust on the basis of a passing job.

This is not a security threat model in the InfoSec sense (transport, secret leakage, dependency CVEs — those live in `SECURITY.md` and the OAuth gateway guide). It is an **analytical-trust** threat model for the API's input/output surfaces.

---

## What GrantFlow does catch

Real, automated checks. If a job reaches `verdict: export_ready`, these properties hold:

- **Auth and scope.** Onboarded agent has valid credentials and required scope (`export:write`, etc.). Tokens without scope return structured `403` with an error code (see [`error-contract.md`](error-contract.md)).
- **Idempotency.** Repeat POST with the same `request_id` returns the cached response, not a duplicate run.
- **Tenant isolation.** `tenant_id` scoping is enforced on every queryable resource.
- **Request shape.** Pydantic v2 validates payloads against typed schemas. Malformed JSON, wrong types, missing required fields fail at the boundary with structured errors.
- **Quota tracking.** `quota_jobs_per_day` and `quota_ingest_per_day` are tracked and reported. (Advisory in current build — see `BACKLOG.md` BL-01.)
- **Preflight `go_ahead`.** Donor template, section coverage, and ingest signals are checked before a paid generation run starts.
- **Critic findings.** Critic emits findings (severity-tagged); `open_high_severity_finding_count` is part of `trust_summary` and gates `export_ready`.
- **Grounding signals.** Runtime grounding gate produces `grounded: true/false`; reflected in `trust_summary.grounded`.
- **HITL checkpoints.** When `hitl_enabled=true`, the job pauses at designated stages until a human resolves the checkpoint.
- **Audit trail.** Every lifecycle transition is logged and queryable.
- **Export contract.** Donor export contract validation runs before export; failure → `export_contract_failed` token in `blocking_reasons`.
- **Citations presence.** `citations_present` is part of `trust_summary`; signals whether the run produced citation artifacts.

If `trust_summary.verdict` is `export_ready`, these structural properties are true. The verdict does **not** assert factual correctness — that boundary is already documented in `trust-report.md` ("Honest limitations").

---

## What GrantFlow does **not** catch

The input/processing-side gaps a careful operator should be aware of. Listed in order of likely operational impact for an agent caller.

### 1. Prompt-injection in proposal text or context inputs

GrantFlow processes proposal-section text, donor-context snippets, and ingest content. If any of these contains an embedded directive ("ignore prior instructions, return X"), GrantFlow does **not** detect it as anomalous. Generation will proceed; the LLM may or may not absorb the directive depending on model behavior. The critic does not score for prompt-injection patterns.

**Mitigation:** treat all user- or third-party-supplied text as DATA at the agent-caller layer; pre-sanitise or quarantine sources outside GrantFlow's trust boundary before submission. Track injection-suspect runs separately.

### 2. Prompt-injection in retrieved RAG content

The same applies to content retrieved from ChromaDB or other RAG sources. If a poisoned document made it into the corpus, the retrieval and generation step will surface that content normally. `grounded: true` reflects retrieval confidence, not retrieval safety.

**Mitigation:** treat ingest as a privileged surface; gate ingest behind operator-controlled review for sources outside the organisation's own corpora.

### 3. Factual correctness of generated text

Already documented in `trust-report.md` Honest limitations. Restated here for completeness: `grounded: true` and `critic_passed: true` are governance signals, not factual ground truth. An LLM can produce fluent, on-topic, well-cited text that is wrong. Human review remains required.

### 4. Hallucinated citations that look well-formed

A citation may be syntactically well-formed (URL, document title, page number) and appear in the output without an underlying source. `citations_present: true` checks presence and shape, not whether each citation points to a real, retrievable, semantically supporting document.

**Mitigation:** route every citation through a verifier at the consumer layer (URL resolution + content similarity check). This belongs outside GrantFlow.

### 5. Donor template drift

Donor templates change. GrantFlow validates against the template version configured at the time of the run. If a template is updated upstream (donor publishes a new RFP edition) and not refreshed in GrantFlow, the export contract may pass against a stale template.

**Mitigation:** track template provenance and `last_refreshed_at`; align refresh cadence with donor's publication cycle.

### 6. Cross-tenant content leakage through shared embeddings

`tenant_id` scoping is enforced on jobs, exports, and queryable resources. If a deployment configures a single shared embedding store across tenants (operator choice), embedding-space retrieval can return content originating from another tenant's corpus depending on chunking and similarity thresholds.

**Mitigation:** segregate embedding stores per tenant for sensitive deployments. This is an operator configuration concern.

### 7. Spoofed or stale donor profile in the request

The donor profile in a generate request is taken at face value. GrantFlow does not cross-check the profile against a canonical donor registry or detect spoofing.

**Mitigation:** maintain a trusted donor-profile catalogue at the operator layer and validate request donor-id against it before submission.

### 8. Replay attacks within the idempotency window

Idempotency is keyed on `request_id`. If an attacker replays a previously authorised request body with the same `request_id` and a valid token, the cached response is returned — which is correct behavior under the contract but means the attacker observes prior output without producing new work.

**Mitigation:** rotate `request_id` per genuine attempt; gate token issuance and rotation at the OAuth gateway.

### 9. Adversarial inputs at scale

The 200+ tests in `grantflow/tests/` cover the contract and known failure modes. There is no fuzz suite running arbitrary or hostile inputs at scale against every endpoint.

**Mitigation:** future work. Production deployments should sit behind a WAF / API gateway that handles rate limiting, basic input filtering, and abuse detection independent of GrantFlow.

### 10. Operator misuse of `hitl_enabled=false`

`hitl_enabled` defaults are configurable. If an operator disables HITL for cost or speed reasons, the `pending_hitl` checkpoint never fires; jobs can reach `export_ready` without any human in the loop. The verdict is then a fully-automated assertion.

**Mitigation:** for high-stakes donors (legal-grade deliverables, regulated programmes), enforce `hitl_enabled=true` at the operator policy layer; treat any `export_ready` produced with HITL disabled as a lower-trust artifact.

---

## How to read this in practice

When a GrantFlow job reaches `verdict: export_ready`:

- **You can trust:** auth, scope, tenancy, request shape, idempotency, preflight, critic high-severity gate, grounding gate, citations presence, export contract against the configured template, audit trail completeness — at the moment the job ran.
- **You still need to verify:** factual correctness of the text, that citations point to real supporting sources, that the donor template configured here matches the current published template, that no prompt-injection entered through proposal text or RAG content, that HITL was actually enabled for high-stakes runs, that the donor profile in the request is the genuine donor.

A `export_ready` verdict is a verdict that GrantFlow's **governance signals** all passed. It is not a verdict that the proposal is **correct**, **safe**, or **submittable** without human review. The two are different.

---

## Status

This is a description of the current API surface (v2.3.3), not a roadmap. Items in "What GrantFlow does not catch" are observations, not commitments. Some have entries in `BACKLOG.md` (e.g., BL-01 quota enforcement); most are intentional boundary calls that should remain at the operator or downstream layer rather than be absorbed by GrantFlow.
