Claude Marketplaces
SkillsMCP serversMarketplacesDigestTools
Submit

This week in Claude

Every Monday: Claude Code, Agent SDK, MCP, and the Anthropic platform moves worth your time.

Skills by category
Frontend DevelopmentBackend & APIsTesting & QASecurityDevOps & CI/CDGit & Pull RequestsDocumentationCode Review & QualityAI & Agent BuildingSkill Development
MCP servers by category
Sales & MarketingWeb & Browser AutomationDatabasesAI & LLM ToolsCloud & InfrastructureCommunication & MessagingDeveloper ToolsDesign & CreativeDocuments & KnowledgeSearch & Web Crawling
Marketplaces by category
AI Agents & OrchestrationLLM IntegrationDevelopment ToolsFrontend & UIBackend & APIsDatabasesTesting & Code QualityDevOps & CloudSecurity & ComplianceGit & Version Control
Claude Marketplaces

An independent directory of skills, plugins and MCP servers for Claude Code. Not affiliated with Anthropic.

Browse

  • Skills
  • MCP servers
  • Marketplaces
  • Weekly digest
  • Skill index
  • MCP index
  • Marketplace index

Site

  • About
  • Tools
  • Submit
  • Feedback
  • Privacy
  • llms.txt
  • Plugins reference

Maker

  • Snug
  • Agent Caffeine
  • knobs
  • Wax
  • Vectoys
  • mertduzgun.com
Crafted at
Skills/Backend & APIs
waynesutton avatar

Convex Security Check

waynesutton/convexskills

The convex-security-check skill provides Convex developers with a structured security audit checklist covering authentication, function exposure, argument validation, row-level access control, and environment variable handling. It solves the problem of ensuring Convex applications follow security best practices by offering concrete verification points and code examples for common vulnerabilities. The skill is designed for developers building with Convex who need to validate their application's security posture before deployment.

installs
2.5K
GitHub stars
401
last updated
Aug 21, 2026
View on GitHubSave

Install

$ npx -y skills add waynesutton/convexskills --skill convex-security-check --agent claude-code

Installs into .claude/skills of the current project.

Files

Convex security check

A ten minute pass over convex/ that catches the mistakes that ship most often. The one rule: every exported query, mutation, and action is a public endpoint anyone can call with any arguments, so each one must check identity and ownership or be intentionally anonymous.

Run each grep, read what it surfaces, fix or file. This skill finds problems; it does not map the whole system. For that, hand off to convex-security-audit.

When to reach for this

  • Before merging a pull request that touches convex/
  • After adding or renaming public functions
  • The user says "quick security check", "sanity check the backend", or "anything obviously wrong here"
  • Before a dev to prod push, when there is no time for a full audit

Checklist

Run the commands from the project root. Every grep excludes _generated.

1. Public vs internal

Anything only called by other Convex functions, the scheduler, crons, or webhooks should be internalQuery, internalMutation, or internalAction.

rg -n "export const \w+ = (query|mutation|action)\(" convex --glob '!**/_generated/**'
rg -n "\bapi\.\w+\.\w+" convex --glob '!**/_generated/**'

The second grep finds api.* used inside the backend. Server code scheduling or running a public function is almost always a sign that function should be internal.

  • Every public function has a client that needs to call it
  • No api.* inside ctx.scheduler.*, ctx.run*, or crons.*
  • Admin only operations (role changes, credit grants, deletions across users) are internal

2. Auth

rg -l "= (query|mutation|action)\(" convex --glob '!**/_generated/**' \
  | xargs rg -L "getUserIdentity|getCurrentUser|authedQuery|authedMutation"

Files listed contain public functions and no auth call at all. Open each one. A public post list is fine anonymous. Anything that returns or writes user data is not.

  • Every public function checks identity or is documented as intentionally anonymous
  • Auth helpers throw or return early when identity is missing
  • Roles come from the users table, never from client arguments

3. Validation

rg -nU "(query|mutation|action)\(\{\s*handler" convex --glob '!**/_generated/**'
rg -n "v\.any\(\)" convex --glob '!**/_generated/**'

The first grep finds functions whose definition starts with handler, meaning no args. The second finds v.any(), which turns off validation for that field.

  • Every function has args and returns validators
  • No v.any() on arguments that reach the database or an external API
  • Return validators list fields explicitly so passwordHash, stripeCustomerId, and internal flags cannot leak

4. Ownership and IDs

v.id("tasks") proves the string is a valid ID for that table. It does not prove the caller owns the document.

rg -n "ctx\.db\.(get|patch|delete|replace)\(args\." convex --glob '!**/_generated/**'
rg -n "userId: v\.(id|string)\(" convex --glob '!**/_generated/**'

For each hit in the first grep, find the ownership comparison between the read and the write. For the second, a public function that accepts the caller's own userId as an argument is trusting the client to say who it is.

  • Every get, patch, delete, replace by a client supplied ID is followed by an ownership or membership check
  • Caller identity is derived from ctx.auth, never accepted as an argument
  • Lists use withIndex on the owner field, not a full scan plus filter

5. Secrets

rg -n -i "(sk_live|sk_test|whsec_|AKIA[0-9A-Z]{16}|-----BEGIN|api[_-]?key\s*[:=]\s*['\"][A-Za-z0-9])" convex src --glob '!**/_generated/**'
rg -n "process\.env\." src

Anything in src/ that reads process.env or import.meta.env ships to the browser. Only deployment URLs and public client IDs belong there.

  • No secret literals in convex/, src/, tests, or fixtures
  • Secrets read from process.env inside the action or HTTP action that uses them
  • Dev and prod deployments use different keys

6. HTTP and storage

rg -n "http\.route|httpAction\(" convex/http.ts
rg -n "storage\.(generateUploadUrl|getUrl)" convex --glob '!**/_generated/**'
  • Every http.ts route verifies its caller (webhook signature, bearer token, or getUserIdentity) before parsing the body
  • Routes call internal.*, not api.*
  • generateUploadUrl requires auth
  • getUrl is called on a storage ID read from a document the caller owns, never on a storage ID passed by the client

One fix, before and after

The most common finding: auth is checked, ownership is not.

Before:

export const updateTask = mutation({
  args: { taskId: v.id("tasks"), title: v.string() },
  returns: v.null(),
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new ConvexError("Sign in required");
    // any signed in user can rename any task
    await ctx.db.patch(args.taskId, { title: args.title });
    return null;
  },
});

After:

import { mutation } from "./_generated/server";
import { v, ConvexError } from "convex/values";
import { getCurrentUser } from "./lib/auth";

export const updateTask = mutation({
  args: { taskId: v.id("tasks"), title: v.string() },
  returns: v.null(),
  handler: async (ctx, args) => {
    const user = await getCurrentUser(ctx); // throws when signed out
    const task = await ctx.db.get(args.taskId);
    // same error for missing and not owned, so IDs cannot be probed
    if (!task || task.userId !== user._id) {
      throw new ConvexError({ code: "NOT_FOUND", message: "Task not found" });
    }
    await ctx.db.patch(args.taskId, { title: args.title });
    return null;
  },
});

getCurrentUser looks the user up through a by_tokenIdentifier index using identity.tokenIdentifier and throws when there is no identity. Define it once in convex/lib/auth.ts and use it everywhere.

Common mistakes

MistakeWhy it breaksDo this instead
Checking auth in the React component onlyAnyone can call the function from the dashboard or a scriptCheck in the handler
v.id("users") argument for "the current user"Client can pass any user's IDDerive from ctx.auth.getUserIdentity()
Comparing ownership to identity.emailEmails can be reused or unverifiedCompare to user._id
internalMutation treated as safe on its ownThe public caller may pass unverified IDsCheck the call site too
Fixing one hit and moving onThe same pattern usually appears in siblingsFix all hits from the grep

Hand off to convex-security-audit

Stop and run the full audit when any of these are true:

  • More than two or three findings in steps 2 or 4; the pattern is systemic
  • The app has multi tenant data (orgs, teams, workspaces)
  • http.ts has webhook routes or routes that return user data
  • Files are uploaded and served
  • The user asks for a report, a launch review, or a post incident review

The audit maps auth per function, data access per table, HTTP exposure, storage, scheduler trust, rate limiting, and produces a written findings report. This check does not.

Docs

  • https://docs.convex.dev/llms.txt
  • https://docs.convex.dev/auth/functions-auth
  • https://docs.convex.dev/functions/internal-functions
  • https://docs.convex.dev/functions/validation
SKILL.md on GitHub

Sponsors

SnugThe clipboard manager you and your agent can use, safelyAgent CaffeineClose your lid, come back to finished workWaxBlock anything with supervision, without erasing your iPhoneOpen StepsSponsoredFree and open-source skills that make AI coding agents easier to understand, verify, and control.

Details

Repository
github.com/waynesutton/convexskills
Categories
Backend & APIs, Security, Databases

More from waynesutton/convexskills

All 14
  • Convex File Storage2.4K
  • Convex Migrations2.4K
  • Convex Security Audit1.4K
  • Convex Agents1.4K
  • Avoid Feature Creep1.2K
  • Convex Component Authoring1.1K
  • Convex5.7K
  • Convex Best Practices3.6K
  • Convex Functions2.9K
  • Convex Schema Validator2.8K
  • Convex Realtime2.7K
  • Convex Cron Jobs2.6K
  • Convex Http Actions2.5K

Recommended

More Backend & APIs
1nvidia avatarcuopt-installnvidia/skillsInstall cuOpt for Python, C, or server via pip, conda, or Docker; verify the install. For building cuOpt from source, see cuopt-developer.2.5Kinstalls
2agricidaniel avatarblog-googleagricidaniel/claude-blogGoogle API integration for blog performance: PageSpeed Insights, CrUX Core Web Vitals with 25-week history, Search Console performance, URL Inspection, Indexing2.5Kinstalls
3mastra-ai avatarsmoke-testmastra-ai/mastraCreate a Mastra project using create-mastra and smoke test the studio in Chrome using Chrome MCP server2.5Kinstalls
4browserbase avatarbrowserbase-clibrowserbase/skillsUse the Browserbase CLI (`browse`) for Browserbase Functions and platform API workflows. Use when the user asks to run `browse`, deploy or invoke functions, man2.5Kinstalls
5agricidaniel avatarblog-notebooklmagricidaniel/claude-blogQuery Google NotebookLM notebooks for source-grounded, citation-backed answers from user-uploaded documents. Manages notebook library, handles Google authentica2.5Kinstalls
6android avataradaptiveandroid/skillsInstructions to make or update an app's UI so that it adapts to different Android devices including phones, tablets, foldables, laptops, desktop, TV, Auto and X2.5Kinstalls