본문으로 건너뛰기
cccskills
무료GitHub에 공개

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 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.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md9.0 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

<!-- GENERATED from convex-agents content/capabilities/convex-authz.json — do not edit by hand. -->

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.

Workflow

  1. 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.
  2. 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.
  3. 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.
  4. 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).
  5. 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.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

adapt

무료

Adapt designs to work across different screen sizes, devices, contexts, or platforms. Implements breakpoints, fluid layouts, and touch targets. Use when the user mentions responsive design, mobile layouts, breakpoints, viewport adaptation, or cross-device compatibility.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

waynesutton/waynesutton-ai22026년 9월 8일 업데이트

Agent Ready project design context for navigation, docs links, and interface tone. Use when building or reviewing UI in this repo so patterns match the documented product feel.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

waynesutton/waynesutton-ai22026년 9월 8일 업데이트

animate

무료

Review a feature and enhance it with purposeful animations, micro-interactions, and motion effects that improve usability and delight. Use when the user mentions adding animation, transitions, micro-interactions, motion design, hover effects, or making the UI feel more alive.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

waynesutton/waynesutton-ai22026년 9월 8일 업데이트

arrange

무료

Improve layout, spacing, and visual rhythm. Fixes monotonous grids, inconsistent spacing, and weak visual hierarchy. Use when the user mentions layout feeling off, spacing issues, visual hierarchy, crowded UI, alignment problems, or wanting better composition.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

waynesutton/waynesutton-ai22026년 9월 8일 업데이트

audit

무료

Run technical quality checks across accessibility, performance, theming, responsive design, and anti-patterns. Generates a scored report with P0-P3 severity ratings and actionable plan. Use when the user wants an accessibility check, performance audit, or technical quality review.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

waynesutton/waynesutton-ai22026년 9월 8일 업데이트

Layout structure for web interfaces, from grouping and alignment to reading order, progressive disclosure, and adaptive breakpoints. Use when structuring a page or component, spacing or aligning controls, deciding what collapses at small sizes, handling RTL layout direction, or reviewing frontend code for layout. Triggers on layout, spacing, alignment, grouping, negative space, whitespace, visual hierarchy, reading order, progressive disclosure, breakpoints, responsive layout, container queries, safe area, full-bleed, edge-to-edge, layout margins, RTL layout, logical properties.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

waynesutton/waynesutton-ai22026년 9월 8일 업데이트

waynesutton의 스킬 모두 보기

이 스킬의 문제 신고