Best for
- A change adds or modifies permission checks, roles, or ownership rules
- A change exposes a new route, action, or admin-only capability
- A query fetches tenant-scoped or user-scoped records and you must confirm scope
event4u-app/agent-config/src/skills/authz-review/SKILL.md
Use when reviewing authorization end-to-end — route → gate → policy → query scope → response filter — before changes to permissions, tenants, ownership, or admin flows.
Decision brief
Grounded corpus (Tier-1 consultation): the threat corpus's authorization + tenancy rows (IDOR, mass-assignment escalation, unscoped queries, sealed job context — each with negative tests) come from ./scripts-run /corpus-grounding/scripts/ground ground --manifest /threat-modeling…
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/authz-review"Inspect the Agent Skill "authz-review" from https://github.com/event4u-app/agent-config/blob/0adf49a8ae84b0ff6e2de8759eea43257e020eff/src/skills/authz-review/SKILL.md at commit 0adf49a8ae84b0ff6e2de8759eea43257e020eff. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Collect 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.
Collect 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.
A change adds or modifies permission checks, roles, or ownership rules A change exposes a new route, action, or admin-only capability A query fetches tenant-scoped or user-scoped records and you must confirm scope A bug report mentions "user A saw user B's data" or "non-admin ac…
For every entrypoint, analyze the authorization chain and record what you find:
Do not list generic findings ("should use policies") — always anchor to a file:line and a specific actor who can reach the gap.
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 98/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 7 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
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,
data-exposure-review,
judge-security-auditor,
security,
security-audit — sibling review / implementation skills.Alternatives
coreyhaines31/marketingskills
When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program
event4u-app/agent-config
Grounded design brief from the adopted corpus — style, WCAG-checked color tokens, typography, layout pattern, anti-patterns. Use on ui-design-brief or any which-style/palette/font/chart decision.
event4u-app/agent-config
Use BEFORE writing or editing any non-trivial UI — inventories components, design tokens, shadcn primitives, and reusable patterns into state.ui_audit. Hard gate for the ui directive set.
event4u-app/agent-config
Use BEFORE writing/changing tests, adding mocks, or test-only methods on production classes — vs mocking-the-mock, production pollution, partial mocks, and overfit/tautological assertions