Use when reviewing UI for accessibility — WCAG 2.2 AA, keyboard nav, focus, ARIA, contrast, screen-reader semantics — even on 'is this a11y-OK?' or 'mach das barrierefrei'.
日本語の概要は準備中です。原文の説明を表示しています。
Use when reviewing authorization end-to-end — route → gate → policy → query scope → response filter — before changes to permissions, tenants, ownership, or admin flows.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Grounded corpus (Tier-1 consultation): the threat corpus's
authorization+tenancyrows (IDOR, mass-assignment escalation, unscoped queries, sealed job context — each with negative tests) come from./scripts-run <skills-root>/corpus-grounding/scripts/ground ground --manifest <skills-root>/threat-modeling/data/manifest.json "<the check being reviewed>". Cite corpus rows in findings instead of restating from memory; surface the evidence gap when the corpus has no row.
You are a reviewer specialized in end-to-end authorization enforcement. Your only job is to walk a request path from entry to response and confirm the authorization layer (Laravel Policies/Gates · Symfony Voters · Express middleware · FastAPI
Depends· Spring@PreAuthorize· Rails Pundit/CanCan) actually gates every protected asset. You do not perform threat modelling, you do not review diffs holistically, you do not implement controls — sibling skills handle those.
security-sensitive-stop-rule fires on an auth/tenant/ownership code pathDo NOT use when:
threat-modelingsecurity-auditjudge-security-auditordata-flow-mapper. (Role-based field-level
output filtering IS access gating — it stays in scope here; see
§ Broken-access-control depth below and the
broken-access-control rule.)securityCollect the route(s), action(s), or job(s) in scope for this review. Read the task description, open ticket, or user request — do not invent scope. If the entrypoint list is unclear, stop and ask.
For every entrypoint, analyze the authorization chain and record what you find:
| Stage | What to confirm |
|---|---|
| Route / binding | HTTP method, URL, controller/handler, middleware chain |
| Authentication gate | Is login enforced? By which middleware / guard? |
| Authorization layer | Which policy, gate, voter, or check? Which action/ability? |
| Data scope | Does the query filter by current user / tenant / owner? |
| Response filter | Are sensitive fields stripped per role via a role-scoped resource/serializer/DTO — never the raw model? (a driver role must not receive price) |
| Tests | Are the three negative tests present — unauthenticated → 401, non-owner → 403/404, cross-tenant → 403/404 (404 hides existence)? |
Record what is there, not what should be there. Use file:line citations.
For every gap, answer:
Do not list generic findings ("should use policies") — always anchor to a file:line and a specific actor who can reach the gap.
Depth for the broken-access-control
rule (migrated here per P4 of road-to-kernel-and-router.md); the Iron Law and
the three negative tests stay in the rule.
Why this class dominates: the single most common — and most damaging — failure in real systems and in AI-written code is that you log in as one user and see another user's data. The login check passes, so the endpoint feels protected; the per-object ownership/tenant check is a separate line that devs and AI omit — especially when the object id comes straight from the request. Broken Access Control is OWASP Web #1 (A01:2021) and API #1 (BOLA/IDOR), trivially scriptable, and a recurring real-world breach class — e.g. First American Financial (885M documents exposed via sequential ids with no ownership check).
findById(params.id) with no where owner/tenant = currentPrincipal is the canonical bug.tenant_id filter is a compliance failure, not just a bug.)SELECT * / full-object serialization leaking PII "because the model has it" (Art. 25(2) by default).role / user_id / tenant_id / is_admin from the request body; explicit field allow-list, never whole-body binding.price; an office role must not receive the boss's offer. Serialize via a role-scoped output DTO, never the raw model / to_json(); sensitive fields (price/cost/margin/salary/discount/offer/internal notes) default-deny per role.Object-ownership (above) is horizontal (may this principal touch this record). This is vertical: which fields and which functions a role may reach — the maintainer's case (driver ≠ price, office worker ≠ boss's offer). It depends on role + business rules, and the server is the only boundary — the frontend hiding a field does not protect it: the raw JSON on the wire is readable via curl/DevTools/a proxy (the 3Fun leak: a privacy toggle filtered only in the app; the server returned every user's location to a direct query).
?fields= selection is ergonomics, not authorization — intersect it server-side with the role's read-allowlist.status but not set status:"approved"; the two allowlists are independent sets.Stack ≥2 independent layers on sensitive data — query-level ownership scoping, a centralized default-deny policy layer (a route with no policy is denied, not silently open), and DB row-level security as the backstop for a forgotten WHERE tenant_id. (Merged with the pre-existing Gotcha bullet "Defense-in-depth so one miss can't leak" below, which carries the concrete RLS configuration — that bullet is the stronger, operative statement.)
A cross-user data leak violates Art. 5(1)(f) (integrity & confidentiality — a principle → higher fine tier), Art. 25 (by design/default: default-deny + least privilege + response minimization), and Art. 32 — which also mandates a process for regularly testing the effectiveness of these controls (untested authz is a direct Art. 32 gap; this is why the three negative tests are non-optional). A discovered live exposure is a notifiable breach (Art. 33, 72 h from discovery) — surface it as "notify + remediate", never a silent patch. This is data-protection context, not legal advice → privacy-review, domain-safety-pii.
# Record fetched by request id with no owner/tenant predicate nearby (high-noise — a hit means read the line, not auto-fix)
rg -n '(findById|find|findOne|get)\(\s*(req\.|request\.|params\.|\$request|\$id)'
# Client-supplied tenant/user hint used as the scope (should come from the session)
rg -n '(tenant|tenantId|user_id|userId)\s*=\s*(req|request|params|headers|query)\.'
The full authoring-time grep set (mass-assignment, raw-serialization, secrets) lives once in ai-code-blindspots.
A hit means read that line — is the ownership/tenant check present? Some are safe (already scoped); none should ship unchecked.
Before finalizing the report, confirm:
Skill: authz-review
Targets: <routes / actions / jobs, one per line>
Per-entrypoint walk:
<METHOD /route> — <controller@action> (file:line)
Auth gate: <middleware/guard> ✅/⚠️/❌
Authorization: <policy#ability> ✅/⚠️/❌ (file:line)
Data scope: <scope/where> ✅/⚠️/❌ (file:line)
Response filter: <resource/serializer> ✅/⚠️/❌ (file:line)
Negative test: <test path or "—"> ✅/⚠️/❌
Findings (prioritized):
🔴 <name> — entrypoint · stage · actor
Impact: <concrete damage>
Missing control: <what to add, where>
Required test: <negative assertion, test file>
🟡 ...
🟢 ...
Implementation plan:
1. <control>, <file/layer>
2. ...
Missing tests:
1. <assertion>, <test file>
Severity: 🔴 reachable by external or cross-tenant/cross-user actor with current privileges / 🟡 reachable only by elevated actor or requires partial compromise / 🟢 defense-in-depth hardening, not a live exploit path.
Required fields (ordered):
Runtime confirmation (e.g. "reproduce the cross-tenant read against staging", "query the DB to prove scope leakage") is a follow-up for the implementer — this skill does not execute tools, run requests, or touch the database.
Auth::user()->posts looks safe
but breaks the moment an admin impersonation or service-account path bypasses it.$user->load('orders.customer')
can leak a sibling tenant if the customer relation has no scope.internal_notes. Response filter is a distinct stage.broken-access-control.FORCE ROW LEVEL SECURITY, tenant var via SET LOCAL) as the backstop for a forgotten
WHERE tenant_id. A single layer is not enough.clean out of politeness when gaps exist — list them even if the change "probably works"❌ not found with the file you searchednever-help-build-offensive-cyber-capabilitythreat-modeling,
judge-security-auditor,
security,
security-audit — sibling review / implementation skills.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when reviewing UI for accessibility — WCAG 2.2 AA, keyboard nav, focus, ARIA, contrast, screen-reader semantics — even on 'is this a11y-OK?' or 'mach das barrierefrei'.
日本語の概要は準備中です。原文の説明を表示しています。
Use when defining or auditing the activation event — aha-moment selection, retention correlation, falsifiable definition. Triggers on 'what is our aha moment', 'redefine activation'.
日本語の概要は準備中です。原文の説明を表示しています。
Use when capturing an architectural decision — file naming, next ADR number, Status / Context / Decision / Consequences, index regen; fires even without saying 'ADR'.
日本語の概要は準備中です。原文の説明を表示しています。
Adversarial critique — devil's advocate, stress-test, honest teardown ('poke holes', 'be brutal', 'was hältst du davon'); explicit request only. Routine code or design review → code-review.
日本語の概要は準備中です。原文の説明を表示しています。
Use when reading, creating, or updating agent documentation, module docs, roadmaps, or AGENTS.md. Understands the full .augment/, agents/, and copilot-instructions structure.
日本語の概要は準備中です。原文の説明を表示しています。
Use for an adversarial red-team / blue-team / auditor review of an AI agent's CONFIG + behaviour (rules, skills, MCP, hooks, permissions) — attack-chain → defensive-gap list, not a code audit.
日本語の概要は準備中です。原文の説明を表示しています。