architecture-threat-model
Skill1 starsChanged 15 days agoMITView on GitHub
Map trust boundaries, tenant isolation, database Row-Level Security and environment scaffolding, then build a STRIDE threat model before auditing individual lines. Use at the start of a full audit, on a new codebase, or when designing a feature that touches auth, tenancy or data ownership.
- Reads credentials
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
Run this first. Line-level findings without an architectural map produce a list of symptoms with no sense of which ones matter.
- Distinctive: line 39
Test it properly: create two accounts, take a resource ID from account A, request it while authenticated as account B.
- Very specific: line 58
No private key, database URL or service-role key in any NEXT_PUBLIC_*, VITE_*, EXPO_PUBLIC_* or REACT_APP_* variable — those are compiled …
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Architecture, Tenancy & STRIDE Threat Model
Run this first. Line-level findings without an architectural map produce a list of symptoms with no sense of which ones matter. A missing aria-label and a missing tenant filter are not the same kind of problem, and only the map tells you which is which.
When to Trigger
- Stage 1 of the master
vibe-aegisloop - A codebase you have not audited before
- Designing anything touching authentication, multi-tenancy, roles or data ownership
- The user asks "is my architecture sound?", "where are my weak points?", "threat model this"
1. Map Before You Hunt
Produce .aegis/THREAT_MODEL.md containing:
Entry points — every way data gets in: API routes, Server Actions, webhooks, file uploads, auth callbacks, scheduled jobs, websocket handlers, and public pages that read a query parameter.
Trust boundaries — where data crosses from less trusted to more trusted. Browser→server, server→database, server→third party, webhook→server. Each crossing is where validation and authorisation must live.
Assets — what an attacker actually wants: user records, payment details, API keys, generated content, admin capability, the ability to spend your model budget.
Actors — anonymous visitor, authenticated user, another tenant's user, admin, the payment provider, a compromised dependency.
2. Tenant Isolation (the one that ends companies)
In a multi-user app, the question is not "can a stranger get in" but "can user A read user B's data". This is the most common catastrophic flaw in vibe-coded apps, because the happy path works perfectly — you only ever test with one account.
Audit every query that takes an identifier:
- Is it filtered by the authenticated session's user or tenant, taken from the server-side session and never from the request body?
- Is the filter applied on the server, not in client code or a hidden UI route?
- For predictable IDs (sequential integers), assume enumeration. UUIDs raise the effort; they are not an authorisation control.
Test it properly: create two accounts, take a resource ID from account A, request it while authenticated as account B. If it returns, that is a confirmed breach, not a theoretical one.
3. Database Row-Level Security
With Supabase or any Postgres exposed to clients, RLS is the actual security boundary — the anon key is public by design, so application-layer checks are irrelevant to someone calling the database directly.
For every table in the public schema:
ALTER TABLE <name> ENABLE ROW LEVEL SECURITY;— present, and not disabled later in a migration.- Explicit policies for
SELECT,INSERT,UPDATEandDELETE. A table with only aSELECTpolicy and RLS enabled silently blocks writes; a table with a permissive write policy is wide open. - Policies scoped to
auth.uid()or verified tenant membership. Flag everyUSING (true)on anything non-public. WITH CHECKonINSERT/UPDATE, otherwise a user can write rows that claim to belong to someone else.- Confirm the
service_rolekey is never in client code. It bypasses RLS entirely.
Remember RLS is only enforced on the anon/authenticated roles. Server code using the service key must do its own scoping — enabling RLS does not protect queries that bypass it.
4. Environment & Secret Scaffolding
.env,.env.local,.env.*in.gitignoreand.dockerignore. Only.env.examplewith blank values is committed.- No private key, database URL or service-role key in any
NEXT_PUBLIC_*,VITE_*,EXPO_PUBLIC_*orREACT_APP_*variable — those are compiled into JavaScript every visitor can read. - Different credentials for development, staging and production. A shared key means a dev leak is a production breach.
- A documented rotation path. If you cannot rotate a key quickly, a leak becomes an outage.
5. STRIDE Pass
For each entry point, ask all six and record the answer:
| Threat | The question |
| Spoofing | Can someone act as another user? Session fixation, weak reset flows, unverified OAuth state |
| Tampering | Can someone change data they should not? Mass assignment, client-trusted prices, unverified webhooks |
| Repudiation | Could someone deny an action? Are security-relevant events logged immutably? |
| Information disclosure | Can data leak? IDOR, verbose errors, over-fetching APIs, source maps, cross-tenant reads |
| Denial of service | Can one user degrade it for everyone? Unbounded queries, no rate limits, unbounded LLM spend |
| Elevation of privilege | Can a user become an admin? Role from a client-supplied field, missing server-side role checks |
Output
.aegis/THREAT_MODEL.md with the entry-point inventory, trust-boundary diagram (an indented list is fine), asset and actor lists, the RLS table-by-table status, and the STRIDE findings ranked by what an attacker gains, not by how easy they were to spot.
Mark anything you could not verify as UNKNOWN with the evidence you would need. A threat model with honest gaps is useful; one with confident guesses is dangerous, because later stages will trust it.
In this repository12 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- llms-full.txtllms.txt
- llms.txtllms.txt
- ai-llm-security-shieldSkill
- artifact-leak-hunterSkill
- backend-reliability-scaleSkill
- payments-logic-auditorSkill
- production-preflight-gateSkill
- security-redteam-loopSkill
- ui-ux-bug-finderSkill
- vibe-aegisSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

