convex-authz
Audit and harden a Convex app's authorization: identity-from-arg impersonation, missing per-document ownership checks, public queries leaking data by a…
Skill by convex
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/convex-convex-authz-ab9638
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: documents, data, security
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions: not checked yet.
What's inside
- Skill name
convex-authz- Description
- Audit and harden a Convex app's authorization: identity-from-arg impersonation, missing per-document ownership checks, public queries leaking data by a client-supplied id, and writes into a parent/container the caller doesn't own. Scans for the 4 shapes, applies requireIdentity/requireOwner, verifies with tsc. TRIGGER on 'secure my app', 'audit auth/authz', 'who can access this data'. SKIP when there is no convex/ directory.
- License
- Apache-2.0
- Instructions
- 29 lines in SKILL.md · view on GitHub
Files (1)
- SKILL.md
SKILL.md (first lines)
# Convex Authz Auditor/Hardener
A focused authz specialist, not a general reviewer: it finds and fixes the four shapes that account for the largest real-defect cluster measured against generated Convex backends (25 identity-from-arg + 13 missing-ownership-check + 6 PII-leak-by-argument = 44 of 214 confirmed defects, plus the parent-reference-on-write variant of the ownership shape that fixture measurement showed the 3-shape scan misses). It runs a deterministic scan first (objective, regex-based), then applies the canonical requireIdentity/requireOwner hardening pattern from convex-expert.md to every hit, then verifies with tsc. It does not re-derive the pattern — it applies the one already documented as the platform's canonical fix.
## Steps
0. MANDATORY FIRST STEP — check the auth foundation exists before injecting any ctx.auth enforcement: (1) is there an auth.config.ts with a provider? (2) is there a users/identities table keyed to the auth subject (tokenIdentifier/identity.subject)? If EITHER is missing, DO NOT add requireIdentity/requireOwner — on a foundationless app ctx.auth.getUserIdentity() always returns null (enforcement is non-functional: every call 401s, or worse, the check is bypassed/miscompared against a non-subject field like an email string) and a reviewer correctly flags that as a NEW authz defect, not a fix. Instead, on a foundationless app: (a) for privileged/admin operations, convert the public query/mutation to internalQuery/internalMutation (removes public reachability entirely — safe and foundation-free, no ctx.auth needed), and (b) tell the user: 'this app has no auth foundation; run `/add auth` or the auth setup first, then re-run convex-authz to add per-user ownership checks.' Do not run steps 1-3 below against public functions on a foundationless app beyond this internalize-and-defer move. Only when the foundation exists (both auth.config.ts and a subject-keyed users table are present) do you proceed to inject requireIdentity/requireOwner in steps 1-3.
1. SCAN (deterministic, objective-first): for every convex/**/*.ts file (skip convex/_generated/ and .d.ts), grep for the four shapes:
(a) identity-from-arg: a public `query(`/`mutation(` object whose `args` block declares `userId`/`actorId`/`ownerId`/`authorId`/`accountId` typed `v.id(...)`, where the function's whole block (args + handler) has zero `ctx.auth` reference. Regex: `/\b(userId|actorId|ownerId|authorId|accountId)\s*:\s*v\.id\(/` inside an `args: { ... }` block paired with an absent `/\bctx\.auth\b/` anywhere in the enclosing `(query|mutation)\(\s*\{ ... }` block (word-boundary excludes internalQuery/internalMutation by construction).
(b) missing-ownership-check: a public `query(`/`mutation(` whose handler loads a document via `ctx.db.get(args.<xId>)` (an `_id`-typed arg) and then calls `ctx.db.patch`/`ctx.db.delete`/`ctx.db.replace` on that same id, or returns the doc's fields directly, with no comparison of any `<doc>.<ownerField>` against an identity value anywhere in the block (no `===`/`!==` involving `identity.subject` or a `ctx.auth` derived value).
(c) PII-leaking public query: a public `query(` whose `returns` (or the raw doc it returns) includes a sensitive-looking field (`email`, `revenue`, `ssn`, `password`, `token`, `auditLog`, `dashboard`-shaped aggregate) and the query is parameterized by a client-supplied id with no `ctx.auth` check gating access to that id's own scope.
(d) parent-reference ownership on write: a public `mutation(` whose args include a `v.id(...)` of a parent/container table (`projectId`, `boardId`, `teamId`, `orgId`, `listId`, `folderId`, `conversationId`, `accountId`, ...) that the handler uses as a foreign key in a `ctx.db.insert`/`ctx.db.patch` — attaching or moving a child row into that container — without verifying the caller owns (or is a member of) the referenced parent doc. Creating a row inside someone else's container is the same defect as mutating their row: fixing WHO the caller is (shape a) does not fix WHERE they may write. After handling shapes a-c, re-audit every REMAINING `v.id(...)` arg in every public mutation for this shape — shape-a fixes routinely leave the parent id arg behind, still unchecked.
Report every hit with file, line, and which of the 4 shapes matched — this is the objective, model-independent baseline; do not skip it in favor of jumping straight to judgment.
2. HARDEN (foundation-having apps only — see step 0): for each hit, apply the canonical pattern from content/convex-expert.md verbatim — do not invent a new helper. Add (if absent) `convex/model/auth.ts` exporting `requireIdentity(ctx)` (throws 401 if `ctx.auth.getUserIdentity()` is null; returns the identity) and `requireOwner(ctx, doc)` (throws 404 if doc is null, throws 403 if `doc.ownerId !== identity.subject`, else returns doc). Rewrite each flagged function: replace the client-supplied identity arg with `requireIdentity(ctx)`; wrap each `_id`-keyed read/mutate with `requireOwner(ctx, await ctx.db.get(args.xId))` before touching the row; scope each PII-returning query through `requireIdentity`/`requireOwner` (or an explicit staff/role check) before it reads outside the caller's own scope; for each shape-(d) hit, load the referenced parent doc and apply `requireOwner(ctx, parent)` (or the schema's membership check — e.g. `participantIds.includes(user._id)` — when the container models members as an array) BEFORE inserting/patching the child row. When the schema keys ownership by a `users` row id rather than the raw subject, resolve the caller's `users` row first (via the subject-keyed index) and compare against `user._id` — comparing an `Id<"users">` field to `identity.subject` never matches and silently breaks enforcement. Never widen scope — an internal/admin function that legitimately operates on an arbitrary user stays `internalQuery`/`internalMutation`, never public; leave it unflagged and unchanged.
3. VERIFY: run `npx tsc --noEmit` (or the project's typecheck script) after edits; a hardening pass that doesn't typecheck is not done. Then re-run the step-1 scan to confirm 0 remaining hits (the fixed shapes no longer match the regexes because `ctx.auth` now appears in-block and ownership comparisons now exist).
4. Report findings grouped by the 4 rule shapes with file:line, explain why each is exploitable (who could impersonate whom / read whose data), and show the concrete diff applied (or, on a foundationless app, the internalize-and-defer diff plus the auth-setup nudge) — never just describe the fix in prose.
## Rules
- MANDATORY FIRST STEP: before injecting requireIdentity/requireOwner, verify the auth foundation exists — an auth.config.ts with a provider AND a users/identities table keyed to the auth subject. If either is missing, do not add ctx.auth-based enforcement (it's non-functional or mismatched and creates a NEW authz defect); instead convert flagged public admin/privileged functions to internalQuery/internalMutation and tell the user to run auth setup first, then re-run convex-authz.
- Scan objectively before judging — run the 4 deterministic greps first; don't skip straight to LLM judgment, and don't let a clean scan stop you from still eyeballing internal/admin exemptions.
- Identity always comes from ctx.auth, never from a client-supplied argument — the one legitimate exception is an internalQuery/internalMutation/internalAction that is never exposed publicly.
- Every read or mutate keyed by an _id argument must verify ownership server-side (requireOwner or an inlined equivalent comparison) before touching the row — being logged in is not the same as owning this row.
- Any v.id(...) argument a public mutation uses as a foreign key when inserting or moving a row must have the referenced parent's ownership (or membership) verified against the caller first — creating a child row inside someone else's project/board/account is the same defect as mutating their row, and it survives an identity-from-arg fix unless checked separately.
- Never leave a public query that returns PII/financial/audit data reachable by an unauthenticated or cross-account client-supplied id.
- Reuse requireIdentity/requireOwner from content/convex-expert.md verbatim — do not fork a parallel helper or invent new error semantics.
- Always verify with tsc after hardening; a fix that doesn't typecheck is not shipped.
- This is a targeted authz pass, not a general code review — do not expand scope into performance/schema/validator findings; hand those to convex-reviewer.
- SKIP entirely when there is no convex/ directory in the project.From convex/convex-backend-skill, Apache-2.0.
More from convex/convex-backend-skill
- 0.620score
labs-quickstart
convex
LABS — scaffold a running Next.js + shadcn Convex app with passkey sign-in and a live Chef feedback panel, then build and verify it locally.
SkillAFreshness: A★ 6Claude Code +9 - 0.612score
improve-convex-plugin
convex
Send THIS coding session's transcript (Claude Code or Codex) to the Convex quickstart backend (anteater) for an AI post-mortem that improves the whole system…
SkillAFreshness: A★ 6Claude Code +9 - 0.610score
env
convex
Set + wire deployment env vars / secrets (API keys) for a Convex app — stored in Convex env, read in actions, never hardcoded.
SkillAFreshness: A★ 6Claude Code +9 - 0.577score
quickstart
convex
Scaffold a brand-new Convex app from a one-sentence idea and build it live — a running Next.js + shadcn app with `convex dev` + `next dev` and error watchers…
SkillBFreshness: B★ 6Claude Code +9 - 0.575score
suggest
convex
Proactively suggest the right Convex component when the user hand-rolls what already exists: setInterval polling → crons, counter increments →…
SkillBFreshness: B★ 6Claude Code +9 - 0.570score
agent
convex
Add an AI agent / chatbot / RAG backend on Convex with @convex-dev/agent (durable threads, messages, tools, vector search).
SkillBFreshness: B★ 6Claude Code +9 - 0.563score
design
convex
Design and build reactive, type-safe, production-grade backends on Convex.
SkillBFreshness: B★ 6Claude Code +9 - 0.530score
add
convex
Add a capability to the CURRENT Convex app — consults the served Convex capability catalog for always-current procedures (billing, crons, auth, agent, search…
SkillCFreshness: C★ 6Claude Code +9 - 0.530score
domains
convex
Wire a domain the user ALREADY OWNS (GoDaddy/Namecheap/Cloudflare/…) to their Convex app: exact DNS records, custom-domain attachment, auth-origin rebind.
SkillCFreshness: C★ 6Claude Code +9 - 0.525score
workflow
convex
Build a durable multi-step pipeline on Convex where each step runs in order and is retried independently on failure (transcribe→summarize→email, ETL, order…
SkillCFreshness: C★ 6Claude Code +9 - 0.525score
billing
convex
Add Stripe billing/payments/subscriptions to a Convex app via @convex-dev/stripe — checkout action, auto-verified webhook, server-side subscription gating.
SkillCFreshness: C★ 6Claude Code +9 - 0.525score
auth
convex
Add authentication to the current Convex + web app — passkeys by default (OAuth/password optional), wired end to end incl.
SkillCFreshness: C★ 6Claude Code +9
Signals
- Stars
- 6
- Forks
- 8
- Open issues
- 7
- Last commit (this folder)
- Aug 28, 2026 (2 months ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- Apache-2.0
- Repository
- github.com/convex/convex-backend-skill
- Website
- convex.dev
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
Same skill elsewhere
Copies of this SKILL.md published by others; search shows only one of them.
More from convex
- 0.666score
convex-improve-convex-plugin
convex
Send this coding session's transcript to the Convex team for an AI post-mortem that improves the quickstart system.
SkillAFreshness: A★ 66Claude Code +9 - 0.663score
convex-deploy-guard
convex
Classify + announce the target Convex deployment before any deployment-affecting command; fresh explicit consent for prod actions; session read-only mode.
SkillAFreshness: A★ 66Claude Code +9 - 0.660score
convex-env
convex
Set and wire Convex deployment env vars / secrets for the app.
SkillAFreshness: A★ 66Claude Code +9 - 0.628score
convex-create-component
convex
Builds reusable Convex components with isolated tables and app-facing APIs.
SkillBFreshness: B★ 66Claude Code +9 - 0.626score
convex-authz
convex
Audit and harden a Convex app's authorization: identity-from-arg impersonation, missing per-document ownership checks, public queries leaking data by a…
SkillBFreshness: B★ 66Claude Code +9 - 0.626score
convex-add
convex
Add a capability to the CURRENT Convex app — consults the served Convex capability catalog for always-current procedures (billing, crons, auth, agent, search…
SkillBFreshness: B★ 66Claude Code +9
Cite this page
convex-authz skill. Agent Mart. https://agentmart.dev/skills/convex-convex-authz-ab9638 (last updated 2026-10-24)