Security Requirements & Threat Modeling Policy
Document control
| Field | Value |
|---|---|
| Owner | Ron Benisty — CTO & CSO (ron.b@iontwrks.com) |
| Status | Approved |
| Version | 1.0 |
| Classification | Confidential |
| Approved by | Ron Benisty — CTO & CSO |
| Approval date | 2026-05-26 (Tuesday) |
| Last reviewed | 2026-05-26 |
| Review cycle | Annual — next review due May 2027 |
| Parent policy | Secure SDLC (SSDLC) |
Satisfies ISO/IEC 27001:2022 A.8.26 (application security requirements) and reinforces A.8.27 (secure architecture & engineering principles). Satisfies NIST SSDF PW.1 (design software to meet security requirements) and PW.2 (review the design to verify compliance). Closes Gap 6 of the SSDLC gap analysis.
1. Purpose
Two related disciplines, combined into one practice:
- Security Requirements — for every meaningful chunk of new work, write down what security properties must hold before code starts. Data classification, authn/authz needs, audit logging, encryption, tenant isolation.
- Threat Modeling — for the same chunk of work, run a structured "what could go wrong?" analysis at the design phase, using STRIDE against a data-flow diagram. The output refines and supplements the requirements.
The two halves go together because the requirements are the answers to threat modeling.
2. Scope — what triggers a threat model
| Triggers a threat model | Does not trigger |
|---|---|
| A new epic — a substantial chunk of new functionality (a new portal section, a new AI workflow, a new external integration, a new background-worker family, a new public API endpoint family) | A normal feature PR inside an existing epic with no new trust boundary |
| Material design change to an existing epic — a new trust boundary, a new data flow, a new sub-processor | Bug fix |
| Adoption of a new sub-processor that handles tenant data | Refactor with no behavioral change |
| A new tenant-isolation pattern or a change to the existing one | A documentation change |
When in doubt, ask: does this introduce a new trust boundary, a new data flow, or a new piece of sensitive data? If yes, threat-model.
3. Data classification
Every security-requirements document must classify the data it touches according to these four tiers:
| Tier | Examples | Handling |
|---|---|---|
| Public | Marketing copy, open-source framework PDFs imported as reference, public CVE feeds | No special handling; safe in any environment |
| Internal | S.E.T's own source code, runbooks, architecture docs, SBOMs, scan reports | Repo + internal systems; not for public sharing |
| Confidential | Tenant data, evidence files, security findings, audit logs, generated policies, BCP plans, vendor responses | Production-only; tenant-scoped; encryption at rest + in transit; access logged |
| Restricted | Credentials, API keys, JWT signing keys, KMS keys, PII (names, emails, phone numbers, identity numbers), MFA seeds | Production-only; AWS Secrets Manager / KMS; never logged; never copied to non-prod; access alerted on |
Higher tiers inherit the rules of lower tiers.
4. When threat modeling runs
The threat model must exist and be CTO & CSO-approved before the first PR of the epic merges to develop. Prototype / spike PRs are permitted to land on a feature branch without one, but cannot reach develop or main without the approved threat model.
Idea → Design draft → Threat model + Security requirements (this policy)
→ CTO & CSO approval → Implementation PRs (per Change Management)
→ Nonprod → Production
A threat model is re-reviewed on material design change: a new trust boundary, a new external system, a new tenant-data shape, or a new sub-processor.
5. Process — six steps
- Open the threat-model file at
docs/threat-models/{epic-name}.mdfrom the template. - Draw the data-flow diagram as Mermaid. Identify every process, data store, data flow, external entity, and the trust boundaries between them.
- Apply STRIDE per element using the rules in §6 — for each element type, identify which STRIDE categories apply and what specific threats exist.
- Document the mitigation for each threat — either an existing control (link to the relevant policy / architecture section) or a new control (which becomes a security requirement on the epic).
- Fill the security-requirements section of the same document, classifying data per §3 and listing concrete requirements derived from the STRIDE analysis.
- CTO & CSO approves by PR review on the threat-model file. Once approved, the first implementation PR may merge.
6. STRIDE per element
The standard mapping — which threat categories apply to which element type. Apply each one:
| Element type | Spoofing | Tampering | Repudiation | Information disclosure | Denial of service | Elevation of privilege |
|---|---|---|---|---|---|---|
| Process (a service / function / worker) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Data flow (a message / API call / queue message) | — | ✓ | — | ✓ | ✓ | — |
| Data store (a DB / S3 bucket / cache / queue) | — | ✓ | ✓ | ✓ | ✓ | — |
| External entity (a user / a sub-processor) | ✓ | — | ✓ | — | — | — |
For each ✓ against an element, ask: can an attacker achieve this against this element? If yes, document the threat + mitigation in §4 of the threat-model file.
7. Threat-model template
Save as docs/threat-models/{epic-name}.md:
# Threat Model — {Epic Name}
**Author**: {name}
**Date**: {YYYY-MM-DD}
**Status**: Draft / Approved
**Approved by (CTO & CSO)**: {name + date once approved}
**Linked epic / issue**: #{issue}
## 1. System overview
One paragraph describing what this epic does and why.
## 2. Data-flow diagram
```mermaid
flowchart LR
User[External: MSSP Admin] -->|HTTPS + JWT| BFF[Process: NestJS BFF]
BFF -->|tenant search_path| DB[(Data store: tenant_xxx schema)]
BFF -->|S3 PUT| Evidence[(Data store: S3 Evidence bucket)]
subgraph TrustBoundary["Trust boundary: AWS VPC"]
BFF
DB
Evidence
end
```
## 3. Trust boundaries
- **External → Cloudflare**: TLS 1.2+; WAF; rate limit
- **Cloudflare → ALB**: mTLS Authenticated Origin Pulls; IP allowlist
- **BFF → tenant schema**: Tenant Context Middleware enforces `search_path`
- **BFF → S3**: IAM role + KMS encryption at rest
## 4. STRIDE analysis
| Element | Threat | Category | Mitigation |
|---|---|---|---|
| BFF | Spoofed JWT bypasses auth | S | WorkOS JWKS verification per Authentication policy |
| BFF → tenant schema | Cross-tenant query if `search_path` not set | T | Tenant Context Middleware + connection-pool `RESET search_path` |
| Evidence bucket | Unauthorized read of another tenant's evidence | I | Per-tenant S3 prefix + IAM policy + KMS CMK; CloudTrail logged |
| BFF | Unbounded query → DoS | D | Cloudflare rate limit + GraphQL complexity ≤ 1 000 |
| External user | Repudiates an action | R | Every mutation logged in tenant `audit_events` (append-only) |
| BFF | User elevates to admin without proper role | E | Per-route RBAC guard; CODEOWNERS-protected role-assignment code |
(Add one row per element/threat pair that has a `✓` in the STRIDE-per-element table.)
## 5. Security requirements derived from §4
1. All requests authenticated via WorkOS JWT — verified server-side via JWKS.
2. All DB queries set `search_path` via Tenant Context Middleware before any query runs.
3. All evidence uploads use a per-tenant S3 prefix + KMS encryption.
4. Every mutation emits an `audit_events` row with actor + tenant + action.
5. GraphQL queries on this epic are subject to depth ≤ 10 + complexity ≤ 1 000.
6. Data classification: **Confidential** (tenant evidence) + **Restricted** (any PII inside evidence).
## 6. Residual risks accepted
Any threat for which mitigation is deferred or accepted — list with the reason.
## 7. Review history
| Date | Reviewer | Outcome |
|---|---|---|
| {YYYY-MM-DD} | CTO & CSO | Approved / Changes requested |
8. Security-requirements-only template (smaller changes)
For changes that touch sensitive data but don't introduce a new trust boundary (e.g. a new field on an existing endpoint), use a slimmed-down requirements document — only §1, §5, §6 of the full template above. CTO & CSO approval still required.
9. Complementary view — MITRE ATT&CK at runtime
STRIDE answers "is the design exploitable?" — applied at design time, per epic, in this policy.
MITRE ATT&CK answers "what are real attackers doing at runtime?" — a catalog of adversary tactics, techniques, and procedures (TTPs) observed in the wild. ATT&CK has its proper home in operations, not design:
- Observability §Security alerting — Logz.io detection rules tag findings with the matching ATT&CK technique ID(s) (e.g.
T1078valid-account abuse,T1190exploitation of public-facing application). - Incident Response §9 — incident records classify observed activity by ATT&CK tactic + technique.
Threat modelers may optionally annotate STRIDE rows in §4 with the ATT&CK technique an attacker would use to realize that threat — useful for downstream detection-rule writers, not required.
10. Evidence + retention
- Each threat model is one Markdown file in
docs/threat-models/, version-controlled with the codebase. - Approval is recorded as the CTO & CSO PR review on that file.
- Retained for the lifetime of the epic + 24 months thereafter, per the Evidence Collection & Retention Policy.
11. Document change history
| Version | Date | Author | Description of change | Approved by |
|---|---|---|---|---|
| 1.0 | 2026-05-26 | Ron Benisty (CTO & CSO) | Initial version — STRIDE-based per-epic threat modeling + four-tier data classification + Markdown+Mermaid templates + design-complete approval gate + cross-reference to MITRE ATT&CK at runtime. | Ron Benisty (CTO & CSO) |