Code security
Skill jjmendezrodriguez/jm-claude-plugin/skills/code-security
Security best practices for TypeScript, React, and Supabase applications. Use this when handling user input, managing secrets, implementing auth with Supabase, configuring RLS policies, validating with Zod, or reviewing code for XSS/injection vulnerabilities. Trigger on: any auth flow, form input, environment variables, API endpoint, or database query. Apply proactively — security is not optional.From its SKILL.md
npx -y skills add jjmendezrodriguez/jm-claude-plugin --skill code-securityAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.7 KB, as published. Nobody here has run it
Security — TS / React / Supabase
Staff Engineer standard: security is a design constraint, not a feature.
1. Security Flow (every critical operation)
1. AUTHENTICATE → Verify identity (Supabase Auth)
2. AUTHORIZE → Check permissions (RLS policies)
3. VALIDATE → Validate inputs (Zod schemas)
4. PROCESS → Execute business logic
5. LOG → Record action (NO sensitive data)
2. Input Validation with Zod
import { z } from "zod";
// ✅ Validate ALL external input at system boundaries
const updateProfileSchema = z.object({
name: z.string().min(2).max(100).trim(),
email: z.string().email(),
bio: z.string().max(500).optional(),
});
// In Edge Function / API handler
const result = updateProfileSchema.safeParse(req.body);
if (!result.success) {
return new Response(JSON.stringify({
type: "ValidationError",
errors: result.error.issues.map((i) => i.message),
}), { status: 400 });
}
// result.data is now typed and sanitized
What to validate:
✅ VALIDATE: ❌ NEVER TRUST:
- Type (string, number) - User input (forms, params)
- Length (min, max) - URL parameters
- Format (email, UUID) - Headers (except from proxy)
- Range (min/max value) - File uploads
- Whitelist (allowed values) - External API responses
3. Secrets Management
// ❌ NEVER — hardcoded secrets
const SUPABASE_KEY = "eyJhbGci...";
// ✅ ALWAYS — environment variables
const SUPABASE_KEY = import.meta.env.VITE_SUPABASE_ANON_KEY;
// ✅ Server-side (Edge Functions) — no VITE_ prefix
const SERVICE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY");
Rules:
VITE_prefix = exposed to browser (anon key only)- Service role key = server-side only (Edge Functions)
.envin.gitignore— always.env.examplecommitted with placeholder values
4. Supabase RLS (Row Level Security)
-- ✅ Users can only read their own data
CREATE POLICY "users_read_own" ON profiles
FOR SELECT USING (auth.uid() = user_id);
-- ✅ Users can only update their own data
CREATE POLICY "users_update_own" ON profiles
FOR UPDATE USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- ❌ BAD — Anyone can read everything
CREATE POLICY "public_read" ON profiles
FOR SELECT USING (true);
RLS checklist:
[ ] RLS enabled on EVERY table with user data
[ ] SELECT policies restrict to own data (unless public)
[ ] INSERT policies validate user_id = auth.uid()
[ ] UPDATE policies use both USING and WITH CHECK
[ ] DELETE policies are restrictive (soft-delete preferred)
[ ] Service role key NEVER used in frontend
5. React XSS Prevention
Never render raw HTML from user input. React auto-escapes JSX expressions ({variable}), which is safe by default.
Avoid setting innerHTML directly. If you must render HTML from a trusted source (e.g., a CMS), always sanitize it first with a library like DOMPurify.
Rules:
- Never interpolate user input into
href,src, orstyleattributes - Validate URLs with
new URL(input)+ whitelist allowed protocols - Use CSP (Content Security Policy) headers as an extra layer
6. Auth Patterns (Supabase)
// ✅ Protect routes — check session before rendering
const ProtectedRoute = ({ children }: { children: ReactNode }) => {
const { session, isLoading } = useAuth();
if (isLoading) return <Spinner />;
if (!session) return <Navigate to="/login" replace />;
return children;
};
// ✅ Edge Function — verify JWT server-side
const { data: { user }, error } = await supabase.auth.getUser(
req.headers.get("Authorization")?.replace("Bearer ", "") ?? ""
);
if (error || !user) return new Response("Unauthorized", { status: 401 });
7. Security Checklist (before every PR)
[ ] No hardcoded secrets (grep for API keys, tokens)
[ ] Zod validates all external input
[ ] RLS policies cover all tables with user data
[ ] No raw HTML rendering without sanitization
[ ] Service role key not exposed to frontend
[ ] .env in .gitignore, .env.example committed
[ ] Auth checked before data access
[ ] No sensitive data in error messages or logs
[ ] CORS properly configured (Supabase dashboard)