@martinffx/atelier 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +7 -2
- package/dist/atelier.js +16 -15
- package/package.json +1 -1
- package/skills/code-debug/SKILL.md +119 -187
- package/skills/code-debug/references/bug-patterns.md +71 -0
- package/skills/code-debug/references/techniques.md +44 -4
- package/skills/code-handoff/SKILL.md +16 -0
- package/skills/oracle-architect/SKILL.md +82 -1
- package/skills/oracle-architect/references/ddd-patterns.md +101 -0
- package/skills/oracle-architect/references/interface-design.md +203 -0
- package/skills/oracle-doubt/SKILL.md +252 -0
- package/skills/oracle-doubt/references/adversarial-prompt.md +47 -0
- package/skills/oracle-security/SKILL.md +225 -0
- package/skills/oracle-security/references/security-patterns.md +236 -0
- package/skills/oracle-security/references/threat-modeling-guide.md +137 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle-doubt
|
|
3
|
+
description: >
|
|
4
|
+
Adversarial review of non-trivial decisions using fresh-context scrutiny.
|
|
5
|
+
Use when correctness matters more than speed, when stakes are high
|
|
6
|
+
(production, security-sensitive logic, irreversible operations), or before
|
|
7
|
+
committing significant architectural or implementation choices.
|
|
8
|
+
user-invocable: true
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Doubt: Fresh-Context Adversarial Review
|
|
12
|
+
|
|
13
|
+
A confident answer is not a correct one. Long sessions accumulate context that quietly turns assumptions into "facts" without anyone noticing. Doubt-driven development is the discipline of materializing a fresh-context reviewer — biased to **disprove**, not approve — before any non-trivial output stands.
|
|
14
|
+
|
|
15
|
+
This is not `/review`. `/review` is a verdict on a finished artifact. This is an in-flight posture: non-trivial decisions get cross-examined while course-correction is still cheap.
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
A decision is **non-trivial** when at least one of these is true:
|
|
20
|
+
|
|
21
|
+
- It introduces or modifies branching logic
|
|
22
|
+
- It crosses a module or service boundary
|
|
23
|
+
- It asserts a property the type system or compiler cannot verify (thread safety, idempotence, ordering, invariants)
|
|
24
|
+
- Its correctness depends on context the future reader cannot see
|
|
25
|
+
- Its blast radius is irreversible (production deploy, data migration, public API change)
|
|
26
|
+
|
|
27
|
+
Apply the skill when:
|
|
28
|
+
|
|
29
|
+
- About to make an architectural decision under uncertainty
|
|
30
|
+
- About to commit non-trivial code
|
|
31
|
+
- About to claim a non-obvious fact ("this is safe", "this scales", "this matches the spec")
|
|
32
|
+
- Working in code you don't fully understand
|
|
33
|
+
|
|
34
|
+
**When NOT to use:**
|
|
35
|
+
|
|
36
|
+
- Mechanical operations (renaming, formatting, file moves)
|
|
37
|
+
- Following a clear, unambiguous user instruction
|
|
38
|
+
- Reading or summarizing existing code
|
|
39
|
+
- One-line changes with obvious correctness
|
|
40
|
+
- Pure tooling operations (running tests, listing files)
|
|
41
|
+
- The user has explicitly asked for speed over verification
|
|
42
|
+
|
|
43
|
+
If you doubt every keystroke, you ship nothing. The skill applies only to non-trivial decisions as defined above.
|
|
44
|
+
|
|
45
|
+
## Loading Constraints
|
|
46
|
+
|
|
47
|
+
This skill is designed for the **main-session orchestrator**, where Step 3 (DOUBT) can spawn fresh-context reviewers via the `task` tool.
|
|
48
|
+
|
|
49
|
+
- **Do NOT add this skill to a persona's `skills:` frontmatter.** A persona that follows Step 3 would spawn another persona — the orchestration anti-pattern explicitly forbidden by `references/orchestration-patterns.md` ("personas do not invoke other personas").
|
|
50
|
+
- **If you find yourself applying this skill from inside a subagent context** (where nested subagent spawn is prevented): the preferred path is to surface to the user that doubt-driven cannot run nested and let the main session handle it. As a last resort only, a degraded self-questioning fallback exists — rewrite ARTIFACT + CONTRACT as a fresh self-prompt with a hard mental separator from your prior reasoning, and walk Steps 1–5. This is **not fresh-context review** (you carry your own context with you), so flag the result as degraded and prefer escalation whenever the user is reachable.
|
|
51
|
+
|
|
52
|
+
## The Process
|
|
53
|
+
|
|
54
|
+
Copy this checklist when applying the skill:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
Doubt cycle:
|
|
58
|
+
- [ ] Step 1: CLAIM — wrote the claim + why-it-matters
|
|
59
|
+
- [ ] Step 2: EXTRACT — isolated artifact + contract, stripped reasoning
|
|
60
|
+
- [ ] Step 3: DOUBT — invoked fresh-context reviewer with adversarial prompt
|
|
61
|
+
- [ ] Step 4: RECONCILE — classified every finding against the artifact text
|
|
62
|
+
- [ ] Step 5: STOP — met stop condition (trivial findings, 3 cycles, or user override)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Step 1: CLAIM — Surface what stands
|
|
66
|
+
|
|
67
|
+
Name the decision in two or three lines:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
CLAIM: "The new caching layer is thread-safe under the
|
|
71
|
+
read-heavy workload described in the spec."
|
|
72
|
+
WHY THIS MATTERS: a race here corrupts user data and is
|
|
73
|
+
hard to detect in QA.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If you can't write the claim that compactly, you have a vibe, not a decision. Surface it before scrutinizing it.
|
|
77
|
+
|
|
78
|
+
### Step 2: EXTRACT — Smallest reviewable unit
|
|
79
|
+
|
|
80
|
+
A fresh-context reviewer needs the **artifact** and the **contract**, not the journey.
|
|
81
|
+
|
|
82
|
+
- **Code**: the diff or the function — not the whole file
|
|
83
|
+
- **Decision**: the proposal in 3–5 sentences plus the constraints it has to satisfy
|
|
84
|
+
- **Assertion**: the claim plus the evidence that supposedly supports it (kept distinct from the Step 1 CLAIM block, which is the orchestrator's hypothesis under scrutiny)
|
|
85
|
+
|
|
86
|
+
Strip your reasoning. If you hand over conclusions, you'll get back validation of your conclusions. The unit must be small enough that a reviewer can hold it in mind in one read — if it's a 500-line PR, decompose first.
|
|
87
|
+
|
|
88
|
+
### Step 3: DOUBT — Invoke the fresh-context reviewer
|
|
89
|
+
|
|
90
|
+
The reviewer's prompt **must be adversarial**. Framing decides the answer.
|
|
91
|
+
|
|
92
|
+
Use the adversarial prompt template from [references/adversarial-prompt.md](references/adversarial-prompt.md). The template is pasted verbatim into the subagent invocation to override any persona's default balanced response shape.
|
|
93
|
+
|
|
94
|
+
**Pass ARTIFACT + CONTRACT only. Do NOT pass the CLAIM.** Handing the reviewer your conclusion biases it toward agreement. The reviewer must independently determine whether the artifact satisfies the contract.
|
|
95
|
+
|
|
96
|
+
#### Cross-model escalation
|
|
97
|
+
|
|
98
|
+
A single-model reviewer shares blind spots with the original author — a colder, different-architecture perspective catches them. Doubt-driven is already opt-in for non-trivial decisions, so within that scope offering cross-model is part of the skill's value, not optional friction.
|
|
99
|
+
|
|
100
|
+
**Interactive sessions: always offer. Never silently skip.**
|
|
101
|
+
|
|
102
|
+
**Step 1: Ask the user**
|
|
103
|
+
|
|
104
|
+
After the single-model review in Step 3 above, but before RECONCILE, pause and ask:
|
|
105
|
+
|
|
106
|
+
> *"Single-model review complete. Want a cross-model second opinion? Options: spawn parallel subagents with different types (oracle + architect), manual external review (you paste it elsewhere), or skip."*
|
|
107
|
+
|
|
108
|
+
This question is mandatory in every interactive doubt cycle — even on artifacts that feel low-stakes. The user — not the agent — decides whether the cost is worth it. The agent's job is to surface the choice.
|
|
109
|
+
|
|
110
|
+
**Step 2: If the user picks parallel subagents — dispatch**
|
|
111
|
+
|
|
112
|
+
Spawn two `task` subagents in parallel with the same adversarial prompt + ARTIFACT + CONTRACT:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
task tool:
|
|
116
|
+
subagent_type: oracle
|
|
117
|
+
task tool:
|
|
118
|
+
subagent_type: architect
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Each subagent starts with isolated context by design. Take both outputs into Step 4 (RECONCILE).
|
|
122
|
+
|
|
123
|
+
**Step 3: If the user skips**
|
|
124
|
+
|
|
125
|
+
Acknowledge the skip in the output (*"Proceeding with single-model findings only"*) and continue to RECONCILE. Skipping is fine; silent skipping is not.
|
|
126
|
+
|
|
127
|
+
**Non-interactive contexts** (CI, scheduled runs):
|
|
128
|
+
|
|
129
|
+
- Cross-model is **skipped**, and the skip must be **announced** in the output: *"Cross-model skipped: non-interactive context."*
|
|
130
|
+
- **Never invoke external subagents without explicit user authorization** — this is a load-bearing safety property.
|
|
131
|
+
|
|
132
|
+
Cross-model adds cost, latency, and tool fragility. The agent surfaces the choice every cycle; the user decides whether this artifact warrants it.
|
|
133
|
+
|
|
134
|
+
### Step 4: RECONCILE — Fold findings back
|
|
135
|
+
|
|
136
|
+
The reviewer's output is data, not verdict. **You are still the orchestrator.** Re-read the artifact text against each finding before classifying — rubber-stamping the reviewer is the same failure mode as ignoring it.
|
|
137
|
+
|
|
138
|
+
For each finding, classify in this **precedence order** (first matching class wins):
|
|
139
|
+
|
|
140
|
+
1. **Contract misread** — reviewer flagged something specifically because the CONTRACT you provided was unclear or incomplete. Fix the contract first, re-classify on the next cycle.
|
|
141
|
+
2. **Valid + actionable** — real issue requiring a change to the artifact. Change it, re-loop.
|
|
142
|
+
3. **Valid trade-off** — issue is real but cost of fixing exceeds cost of accepting. Document the trade-off explicitly so the user sees it.
|
|
143
|
+
4. **Noise** — reviewer flagged something that's actually correct under context the reviewer didn't have. Note it, move on, and ask: would adding that context to the contract have prevented the false flag?
|
|
144
|
+
|
|
145
|
+
A fresh reviewer can be wrong because it lacks context. Don't defer just because it's "fresh."
|
|
146
|
+
|
|
147
|
+
### Step 5: STOP — Bounded loop, not recursion
|
|
148
|
+
|
|
149
|
+
Stop when:
|
|
150
|
+
|
|
151
|
+
- Next iteration returns only trivial or already-considered findings, **or**
|
|
152
|
+
- 3 cycles completed (escalate to user, don't grind a fourth alone), **or**
|
|
153
|
+
- User explicitly says "ship it"
|
|
154
|
+
|
|
155
|
+
If after 3 cycles the reviewer still surfaces substantive issues, the artifact may not be ready. Surface this to the user — three unresolved cycles is information about the artifact, not a reason to keep looping.
|
|
156
|
+
|
|
157
|
+
If 3 cycles is "obviously insufficient" because the artifact is large: the artifact is too big — return to Step 2 and decompose. Do not lift the bound.
|
|
158
|
+
|
|
159
|
+
## Common Rationalizations
|
|
160
|
+
|
|
161
|
+
| Rationalization | Reality |
|
|
162
|
+
|---|---|
|
|
163
|
+
| "I'm confident, skip the doubt step" | Confidence correlates poorly with correctness on novel problems. Moments of certainty are exactly when blind spots hide. |
|
|
164
|
+
| "Spawning a reviewer is expensive" | Debugging a wrong commit in production is more expensive. The check is bounded; the bug isn't. |
|
|
165
|
+
| "The reviewer will just nitpick" | Only if unscoped. Constrain the prompt to "issues that would make this fail under the contract." |
|
|
166
|
+
| "I'll do doubt at the end with `/review`" | `/review` is a final gate. Doubt-driven catches wrong directions early when course-correction is cheap. By PR time it's too late. |
|
|
167
|
+
| "If I doubt every step I'll never ship" | The skill applies to non-trivial decisions, not every keystroke. Re-read "When NOT to Use." |
|
|
168
|
+
| "Two opinions are always better than one" | Not when the second has less context and produces noise. Reconcile, don't defer. |
|
|
169
|
+
| "The reviewer disagreed so I was wrong" | The reviewer lacks your context — disagreement is information, not verdict. Re-read the artifact, classify, then decide. |
|
|
170
|
+
| "Cross-model is always better" | Cross-model catches blind spots a single model shares with itself, but it adds cost and tool fragility. Offer it every interactive doubt cycle — the user decides whether the artifact warrants it. The agent's job is to surface the choice, not to gate it. |
|
|
171
|
+
| "User said yes once, so I can keep invoking subagents" | Each invocation is its own authorization. The artifact, the prompt, and the context change between calls — re-confirm with the user before every run. |
|
|
172
|
+
|
|
173
|
+
## Red Flags
|
|
174
|
+
|
|
175
|
+
- Spawning a fresh-context reviewer for a one-line rename or formatting change
|
|
176
|
+
- Treating reviewer output as authoritative without re-reading the artifact text
|
|
177
|
+
- Looping >3 cycles without escalating to the user
|
|
178
|
+
- Prompting the reviewer with "is this good?" instead of "find issues"
|
|
179
|
+
- Skipping doubt under time pressure on a high-stakes decision
|
|
180
|
+
- Re-spawning fresh-context on an unchanged artifact (you'll get the same findings; you're stalling)
|
|
181
|
+
- **Doubt theater (checkable signal)**: across 2 or more cycles where the reviewer surfaced substantive findings, zero findings were classified as actionable. You are validating, not doubting. Stop and escalate.
|
|
182
|
+
- Doubting only after committing — that's `/review`, not doubt-driven development
|
|
183
|
+
- Hardcoding a subagent invocation without confirming with the user that the approach is acceptable
|
|
184
|
+
- **Silently skipping cross-model in an interactive doubt cycle.** Even when not recommending it, the offer must be visible. Skipping is fine; silent skipping is not.
|
|
185
|
+
- Falling back silently when a subagent errors or is unavailable — surface the failure and let the user redirect
|
|
186
|
+
- Stripping the contract from the reviewer's input
|
|
187
|
+
- Passing the CLAIM to the reviewer (biases toward agreement)
|
|
188
|
+
|
|
189
|
+
## Interaction with Other Skills
|
|
190
|
+
|
|
191
|
+
- **`code-review` / `/review`**: complementary. `/review` is post-hoc PR verdict; doubt-driven is in-flight per-decision. Use both.
|
|
192
|
+
- **`oracle-architect`** / **`spec-research`**: SDD verifies *facts about frameworks* against official docs. Doubt-driven verifies *your reasoning about the artifact*. SDD checks the API exists; doubt-driven checks you used it correctly under the contract.
|
|
193
|
+
- **`oracle-testing`**: TDD's RED step is doubt made concrete — a failing test is a disproof attempt. When TDD applies, that failing test *is* the doubt step for behavioral claims.
|
|
194
|
+
- **`code-debug`**: when the reviewer surfaces a real failure mode, drop into the debugging skill to localize and fix.
|
|
195
|
+
|
|
196
|
+
## Verification
|
|
197
|
+
|
|
198
|
+
After applying doubt-driven development:
|
|
199
|
+
|
|
200
|
+
- Every non-trivial decision (per the definition above) was named explicitly as a CLAIM before standing
|
|
201
|
+
- At least one fresh-context review per non-trivial artifact (a failing test produced by TDD's RED step satisfies this for behavioral claims, per Interaction with Other Skills)
|
|
202
|
+
- The reviewer received ARTIFACT + CONTRACT — NOT the CLAIM, NOT your reasoning
|
|
203
|
+
- The reviewer's prompt was adversarial ("find issues"), not validating ("is it good")
|
|
204
|
+
- Findings were classified against the artifact text (not rubber-stamped) using the precedence: contract misread / actionable / trade-off / noise
|
|
205
|
+
- A stop condition was met (trivial findings, 3 cycles, or user override)
|
|
206
|
+
- In interactive mode, cross-model was **explicitly offered** to the user (regardless of artifact stakes) and the response was acknowledged in the output
|
|
207
|
+
- In non-interactive mode, cross-model was skipped and the skip was announced
|
|
208
|
+
- Any subagent invocation was preceded by user authorization and confirmation of the approach
|
|
209
|
+
|
|
210
|
+
## Usage Examples
|
|
211
|
+
|
|
212
|
+
**Doubt an architectural decision:**
|
|
213
|
+
```
|
|
214
|
+
/atelier-doubt
|
|
215
|
+
CLAIM: "I will use DynamoDB single-table design for the Order service."
|
|
216
|
+
WHY: "Single-table simplifies access patterns but may couple unrelated domains."
|
|
217
|
+
ARTIFACT: "Proposed key schema: PK=ORDER#<id>, SK=METADATA#<id>. All order data in one table."
|
|
218
|
+
CONTRACT: "Must support: 1) lookup by order ID, 2) list by customer, 3) list by status. No cross-domain queries."
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Doubt a code change before commit:**
|
|
222
|
+
```
|
|
223
|
+
/atelier-doubt
|
|
224
|
+
CLAIM: "The retry logic in PaymentService is safe under concurrent requests."
|
|
225
|
+
WHY: "Race here could double-charge customers."
|
|
226
|
+
ARTIFACT: "<paste diff or function>"
|
|
227
|
+
CONTRACT: "Must be idempotent: same paymentId processed twice produces same result, no duplicate charges."
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Doubt a non-obvious assertion:**
|
|
231
|
+
```
|
|
232
|
+
/atelier-doubt
|
|
233
|
+
CLAIM: "This migration is safe to run online without downtime."
|
|
234
|
+
WHY: "Downtime here blocks checkout for all users."
|
|
235
|
+
ARTIFACT: "ALTER TABLE orders ADD COLUMN tracking_id VARCHAR(255); CREATE INDEX idx_tracking ON orders(tracking_id);"
|
|
236
|
+
CONTRACT: "Must not lock table for more than 1 second. Must not fail on 10M row table. Must be backward-compatible with running application code."
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Relationship to Other Skills
|
|
240
|
+
|
|
241
|
+
| Skill | Use When |
|
|
242
|
+
|---|---|
|
|
243
|
+
| **oracle-doubt** | In-flight adversarial review before a decision stands. Catches wrong directions early. |
|
|
244
|
+
| **oracle-challenge** | Critically evaluating an existing approach or decision after it's been made. |
|
|
245
|
+
| **code-review** | Post-hoc PR verdict on a finished artifact. |
|
|
246
|
+
| **oracle-testing** | TDD RED step serves as the doubt mechanism for behavioral claims. |
|
|
247
|
+
| **oracle-thinkdeep** | Deep exploration and alternative discovery for complex decisions (use doubt after thinkdeep narrows to a specific choice). |
|
|
248
|
+
|
|
249
|
+
**Key distinction:**
|
|
250
|
+
- `oracle-doubt` = "Before I commit to this, prove me wrong" (pre-commit adversarial review)
|
|
251
|
+
- `oracle-challenge` = "Is this approach valid?" (critical evaluation of standing decisions)
|
|
252
|
+
- `code-review` = "Judge this finished artifact" (post-hoc verdict)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Adversarial Reviewer Prompt Template
|
|
2
|
+
|
|
3
|
+
Use this prompt when spawning a fresh-context reviewer via the `task` tool.
|
|
4
|
+
The reviewer must receive **ARTIFACT + CONTRACT only** — never the CLAIM or orchestrator's reasoning.
|
|
5
|
+
|
|
6
|
+
## Template
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
Adversarial review. Find what is wrong with this artifact.
|
|
10
|
+
Assume the author is overconfident. Look for:
|
|
11
|
+
- Unstated assumptions
|
|
12
|
+
- Edge cases not handled
|
|
13
|
+
- Hidden coupling or shared state
|
|
14
|
+
- Ways the contract could be violated
|
|
15
|
+
- Existing conventions this might break
|
|
16
|
+
- Failure modes under unexpected input
|
|
17
|
+
|
|
18
|
+
Do NOT validate. Do NOT summarize. Find issues, or state explicitly
|
|
19
|
+
that you cannot find any after thorough examination.
|
|
20
|
+
|
|
21
|
+
ARTIFACT:
|
|
22
|
+
{ARTIFACT}
|
|
23
|
+
|
|
24
|
+
CONTRACT:
|
|
25
|
+
{CONTRACT}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Dispatch via task tool
|
|
29
|
+
|
|
30
|
+
Spawn **parallel** subagents for cross-perspective review:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
# Reviewer 1: oracle perspective
|
|
34
|
+
<task tool call with subagent_type="oracle">
|
|
35
|
+
|
|
36
|
+
# Reviewer 2: architect perspective
|
|
37
|
+
<task tool call with subagent_type="architect">
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Each receives the **same** adversarial prompt above with ARTIFACT and CONTRACT.
|
|
41
|
+
|
|
42
|
+
## Rules
|
|
43
|
+
|
|
44
|
+
- **Never pass the CLAIM** — handing the reviewer your conclusion biases them toward agreement
|
|
45
|
+
- **Never pass your reasoning** — the reviewer must independently determine whether the artifact satisfies the contract
|
|
46
|
+
- **Paste this prompt verbatim** — it overrides any persona's default response shape (which may be balanced/validating)
|
|
47
|
+
- **No session context** — the subagent starts fresh with only this prompt
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oracle-security
|
|
3
|
+
description: Security architecture and threat modeling knowledge. Auto-invokes when designing features that handle untrusted data, authentication, authorization, external integrations, file uploads, or sensitive data. Provides risk assessment frameworks, trust boundary analysis, and security design principles — not implementation code.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# oracle-security: Security Architecture & Threat Modeling
|
|
8
|
+
|
|
9
|
+
## When to Use
|
|
10
|
+
|
|
11
|
+
Auto-invokes when context contains:
|
|
12
|
+
- Authentication, authorization, session management
|
|
13
|
+
- User input, validation, untrusted data
|
|
14
|
+
- External integrations, webhooks, third-party APIs
|
|
15
|
+
- File uploads, data processing
|
|
16
|
+
- Encryption, hashing, secrets, sensitive data
|
|
17
|
+
- Security concerns, vulnerabilities, threats
|
|
18
|
+
|
|
19
|
+
## The Security Mindset
|
|
20
|
+
|
|
21
|
+
### Core Principles
|
|
22
|
+
|
|
23
|
+
1. **Validate at Boundaries** — Every entry point is a trust boundary. Assume everything that crosses it is hostile until proven otherwise.
|
|
24
|
+
|
|
25
|
+
2. **Never Trust the Client** — Client-side validation, hidden fields, and browser headers are UX conveniences, not security controls. The server is the only security boundary that matters.
|
|
26
|
+
|
|
27
|
+
3. **Fail Closed** — Deny by default. When in doubt, reject. When validation fails, stop. When auth is uncertain, deny. "Fail open" is an accidental backdoor.
|
|
28
|
+
|
|
29
|
+
4. **Defense in Depth** — No single control should be the only thing preventing compromise. Layer them so that bypassing one still leaves others.
|
|
30
|
+
|
|
31
|
+
5. **Least Privilege** — Every component should have the minimum access necessary to do its job, and only for the minimum time required.
|
|
32
|
+
|
|
33
|
+
6. **Compartmentalize** — A breach in one area should not automatically grant access to everything else. Isolate by function, data sensitivity, and trust level.
|
|
34
|
+
|
|
35
|
+
### The Trust Boundary Model
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
External World → [Trust Boundary] → Internal System
|
|
39
|
+
↑ ↑
|
|
40
|
+
Validate here Enforce here
|
|
41
|
+
Sanitize here Audit here
|
|
42
|
+
Authenticate here Authorize here
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Trust boundaries exist at every system edge where data or control crosses from a less-trusted to a more-trusted zone:
|
|
46
|
+
|
|
47
|
+
- **API routes / controllers** — Where external requests enter
|
|
48
|
+
- **Event consumers** — Where external events are processed
|
|
49
|
+
- **File processors** — Where external files are handled
|
|
50
|
+
- **External service callbacks** — Where third-party responses enter
|
|
51
|
+
- **Database writes** — When data from external sources persists
|
|
52
|
+
|
|
53
|
+
**Key insight**: Security enforcement should happen as close to the trust boundary as possible. Don't let untrusted data travel deep into your system before validation.
|
|
54
|
+
|
|
55
|
+
## Threat Modeling Quick-Start
|
|
56
|
+
|
|
57
|
+
### Simplified STRIDE
|
|
58
|
+
|
|
59
|
+
For every feature, ask these six questions:
|
|
60
|
+
|
|
61
|
+
| Threat | Question | Example Concern |
|
|
62
|
+
|--------|----------|----------------|
|
|
63
|
+
| **S**poofing | Who could pretend to be someone else? | Fake user IDs, stolen tokens, forged requests |
|
|
64
|
+
| **T**ampering | What could be modified in transit or at rest? | Request payload alteration, data corruption |
|
|
65
|
+
| **R**epudiation | Can actions be denied after the fact? | Missing audit logs, unaccountable changes |
|
|
66
|
+
| **I**nformation Disclosure | What sensitive data could leak? | Error messages, logs, API responses |
|
|
67
|
+
| **D**enial of Service | How could this be overwhelmed or broken? | No rate limits, expensive queries, resource exhaustion |
|
|
68
|
+
| **E**levation of Privilege | Who could gain more access than intended? | Missing authorization checks, parameter tampering |
|
|
69
|
+
|
|
70
|
+
### Attack Tree Thinking
|
|
71
|
+
|
|
72
|
+
For critical features, build a simple attack tree:
|
|
73
|
+
|
|
74
|
+
1. **Goal**: What does the attacker want? (data, access, disruption)
|
|
75
|
+
2. **Paths**: How could they achieve it? (multiple entry points, chained vulnerabilities)
|
|
76
|
+
3. **Barriers**: What stops each path? (validation, auth, rate limits, encryption)
|
|
77
|
+
4. **Gaps**: Where are there no barriers? (missing checks, implicit trust)
|
|
78
|
+
|
|
79
|
+
**Usage**: You don't need a formal diagram. A bullet list of "to steal X, attacker could Y which is blocked by Z, unless they find W" is sufficient for most design reviews.
|
|
80
|
+
|
|
81
|
+
## Risk Proportionality
|
|
82
|
+
|
|
83
|
+
### Assessment Dimensions
|
|
84
|
+
|
|
85
|
+
Consider two factors:
|
|
86
|
+
|
|
87
|
+
- **Impact**: What happens if this is exploited? (reputational damage, financial loss, legal consequences, user harm)
|
|
88
|
+
- **Likelihood**: How easy is exploitation? (public internet access, authenticated only, internal network, physical access required)
|
|
89
|
+
|
|
90
|
+
### Flexible Guidance
|
|
91
|
+
|
|
92
|
+
| Context | Typical Posture |
|
|
93
|
+
|---------|-----------------|
|
|
94
|
+
| Public-facing, unauthenticated | Maximum validation, rate limiting, minimal data exposure, aggressive fail-closed |
|
|
95
|
+
| Authenticated user operations | Standard validation, authorization checks, audit logging, session management |
|
|
96
|
+
| Internal admin tools | Authentication essential, authorization by role, audit everything, additional monitoring |
|
|
97
|
+
| Background processing | Input validation still required, fail-safe defaults, logging for debugging |
|
|
98
|
+
|
|
99
|
+
**Adjust based on your threat model.** A public search box and an internal admin panel have different risks. Don't apply maximum security everywhere — apply *proportional* security everywhere.
|
|
100
|
+
|
|
101
|
+
## Security Architecture Patterns
|
|
102
|
+
|
|
103
|
+
### Defense in Depth
|
|
104
|
+
|
|
105
|
+
Don't rely on a single control. Layer them:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Input → [Validation] → [Authentication] → [Authorization] → [Audit]
|
|
109
|
+
↑ ↑ ↑ ↑
|
|
110
|
+
Reject bad Verify who Check can-do Log did-do
|
|
111
|
+
data they are they have they did
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If any layer fails, the others still provide protection. A validation bypass shouldn't automatically mean unauthorized access.
|
|
115
|
+
|
|
116
|
+
### Least Privilege
|
|
117
|
+
|
|
118
|
+
- Services should have minimum database permissions (read-only where possible, never admin by default)
|
|
119
|
+
- API tokens should have scoped access (not blanket permissions)
|
|
120
|
+
- User sessions should timeout (not indefinite, not excessively long)
|
|
121
|
+
- Background jobs should run with restricted credentials (not application-level access)
|
|
122
|
+
|
|
123
|
+
**Corollary**: When a component needs elevated access temporarily, that access should be explicitly granted and automatically revoked.
|
|
124
|
+
|
|
125
|
+
### Fail-Safe Defaults
|
|
126
|
+
|
|
127
|
+
- Permission denied unless explicitly granted (not granted unless explicitly denied)
|
|
128
|
+
- Reject input that doesn't match expected format (don't try to fix or coerce)
|
|
129
|
+
- Lock account after repeated failures (don't allow infinite attempts)
|
|
130
|
+
- Default to most restrictive CORS, CSP, and network policies (open up explicitly)
|
|
131
|
+
|
|
132
|
+
**Key question**: "If this component fails or is misconfigured, what's the safest default state?"
|
|
133
|
+
|
|
134
|
+
### Compartmentalization
|
|
135
|
+
|
|
136
|
+
- Separate sensitive data from operational data (different stores, different access levels)
|
|
137
|
+
- Use different credentials for different services (one breach doesn't cascade)
|
|
138
|
+
- Isolate file processing from application logic (sandbox, validate before processing)
|
|
139
|
+
- Don't mix admin and user operations in the same endpoints or components
|
|
140
|
+
|
|
141
|
+
## Design Review Questions
|
|
142
|
+
|
|
143
|
+
Ask before implementing:
|
|
144
|
+
|
|
145
|
+
### Data Handling
|
|
146
|
+
- [ ] What data enters the system? Where does it come from? How is it validated?
|
|
147
|
+
- [ ] What data exits the system? Who can see it? Is it filtered appropriately?
|
|
148
|
+
- [ ] What happens to data at rest? Is sensitive data protected?
|
|
149
|
+
- [ ] Are there retention/deletion requirements? How are they enforced?
|
|
150
|
+
|
|
151
|
+
### Access Control
|
|
152
|
+
- [ ] Who can access this feature? How is that authenticated and enforced?
|
|
153
|
+
- [ ] Can users access other users' data? How is that prevented?
|
|
154
|
+
- [ ] Are there different permission levels? How are they checked?
|
|
155
|
+
- [ ] What happens when permissions change (revocation, role change)?
|
|
156
|
+
|
|
157
|
+
### Threat Surface
|
|
158
|
+
- [ ] What new entry points does this feature create?
|
|
159
|
+
- [ ] What existing trust boundaries does this cross?
|
|
160
|
+
- [ ] What external systems does this depend on? What's their security posture?
|
|
161
|
+
- [ ] What happens if those systems are compromised or unavailable?
|
|
162
|
+
|
|
163
|
+
### Failure Modes
|
|
164
|
+
- [ ] What happens when validation fails? (Should fail closed)
|
|
165
|
+
- [ ] What happens when authentication fails? (Should not reveal user existence)
|
|
166
|
+
- [ ] What happens when dependencies fail? (Should degrade safely)
|
|
167
|
+
- [ ] Are errors informative for debugging without being revealing for attackers?
|
|
168
|
+
|
|
169
|
+
## Red Flags & Anti-Patterns
|
|
170
|
+
|
|
171
|
+
### Architectural Smells
|
|
172
|
+
|
|
173
|
+
- **Trusting external input without validation** — Browser headers, webhook payloads, file contents, third-party API responses. All are untrusted until validated.
|
|
174
|
+
|
|
175
|
+
- **Single authorization check at entry** — Checking auth at the route level but not verifying resource ownership on each operation. Every action on a resource needs its own authorization check.
|
|
176
|
+
|
|
177
|
+
- **Errors revealing system internals** — Stack traces, database schemas, file paths, internal IDs in error messages. Debug information belongs in logs, not responses.
|
|
178
|
+
|
|
179
|
+
- **No audit trail for sensitive operations** — If you can't reconstruct who did what after an incident, you can't investigate or recover.
|
|
180
|
+
|
|
181
|
+
- **Broad permissions by default** — Service accounts with admin access, tokens with blanket permissions, users with more roles than they need.
|
|
182
|
+
|
|
183
|
+
- **Security logic in client code** — "The frontend will validate" or "the mobile app won't send that." The client is not a security boundary.
|
|
184
|
+
|
|
185
|
+
### Process Smells
|
|
186
|
+
|
|
187
|
+
- "We'll add security later" — Security retrofitting is 10x harder and 10x more expensive than designing it in.
|
|
188
|
+
- "This is just internal" — Internal tools are prime targets. Attackers specifically look for weak internal systems.
|
|
189
|
+
- "No one would try to exploit this" — Automated attacks are indiscriminate. You don't need to be a target to be compromised.
|
|
190
|
+
- "The framework handles security" — Frameworks provide primitives and tools. You must compose them correctly.
|
|
191
|
+
- "Security slows development" — Insecure code slows you more when you have to stop everything to respond to a breach.
|
|
192
|
+
|
|
193
|
+
## Common Rationalizations
|
|
194
|
+
|
|
195
|
+
| Rationalization | Reality |
|
|
196
|
+
|-----------------|---------|
|
|
197
|
+
| "It's just a prototype" | Prototypes become production. Security habits from day one prevent day-one-hundred emergencies. |
|
|
198
|
+
| "This is an internal tool" | Internal tools are targets. Attackers look for the weakest link, and internal systems are often it. |
|
|
199
|
+
| "We'll add security later" | Later rarely comes. Retrofitting is expensive, error-prone, and usually incomplete. |
|
|
200
|
+
| "The framework handles security" | Frameworks provide primitives. You compose them correctly. They don't secure your application by default. |
|
|
201
|
+
| "No one would target us" | Automated attacks are indiscriminate. Scanners don't care who you are. |
|
|
202
|
+
| "Security slows development" | Insecure code costs more: incident response, legal exposure, user trust loss. |
|
|
203
|
+
|
|
204
|
+
## Verification
|
|
205
|
+
|
|
206
|
+
After designing security-relevant features:
|
|
207
|
+
|
|
208
|
+
- [ ] Threat model documented (even if brief — STRIDE questions answered)
|
|
209
|
+
- [ ] Trust boundaries identified and validation points specified
|
|
210
|
+
- [ ] Input validation strategy defined (where, what, how strict)
|
|
211
|
+
- [ ] Authentication requirements specified (who, how, session management)
|
|
212
|
+
- [ ] Authorization rules documented (who can do what to what)
|
|
213
|
+
- [ ] Failure modes specified (fail closed, not open)
|
|
214
|
+
- [ ] Audit requirements identified (what to log, where)
|
|
215
|
+
- [ ] External dependencies' security posture considered
|
|
216
|
+
- [ ] No secrets or sensitive data in design documents (future attack surface)
|
|
217
|
+
|
|
218
|
+
## See Also
|
|
219
|
+
|
|
220
|
+
- `references/threat-modeling-guide.md` — Extended threat modeling approaches
|
|
221
|
+
- `references/security-patterns.md` — Catalog of security design patterns
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
*Security is not a feature you add. It's a property of the system you design.*
|