AI/skills/security-best-practices/SKILL.md
Provides comprehensive security checklist and patterns. Use when information is needed about security best practices.
npx skillsauth add thesimonho/dotfiles security-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides security best practices and identifies potential vulnerabilities.
const apiKey = "sk-proj-xxxxx"; // Hardcoded secret
const dbPassword = "password123"; // In source code
const apiKey = process.env.OPENAI_API_KEY;
const dbUrl = process.env.DATABASE_URL;
// Verify secrets exist
if (!apiKey) {
throw new Error("OPENAI_API_KEY not configured");
}
.env.local in .gitignoreimport { z } from "zod";
// Define validation schema
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
age: z.number().int().min(0).max(150),
});
// Validate before processing
export async function createUser(input: unknown) {
try {
const validated = CreateUserSchema.parse(input);
return await db.users.create(validated);
} catch (error) {
if (error instanceof z.ZodError) {
return { success: false, errors: error.errors };
}
throw error;
}
}
function validateFileUpload(file: File) {
// Size check (5MB max)
const maxSize = 5 * 1024 * 1024;
if (file.size > maxSize) {
throw new Error("File too large (max 5MB)");
}
// Type check
const allowedTypes = ["image/jpeg", "image/png", "image/gif"];
if (!allowedTypes.includes(file.type)) {
throw new Error("Invalid file type");
}
// Extension check
const allowedExtensions = [".jpg", ".jpeg", ".png", ".gif"];
const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0];
if (!extension || !allowedExtensions.includes(extension)) {
throw new Error("Invalid file extension");
}
return true;
}
// DANGEROUS - SQL Injection vulnerability
const query = `SELECT * FROM users WHERE email = '${userEmail}'`;
await db.query(query);
// Safe - parameterized query
const { data } = await supabase
.from("users")
.select("*")
.eq("email", userEmail);
// Or with raw SQL
await db.query("SELECT * FROM users WHERE email = $1", [userEmail]);
// ❌ WRONG: localStorage (vulnerable to XSS)
localStorage.setItem("token", token);
// ✅ CORRECT: httpOnly cookies
res.setHeader(
"Set-Cookie",
`token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`,
);
export async function deleteUser(userId: string, requesterId: string) {
// ALWAYS verify authorization first
const requester = await db.users.findUnique({
where: { id: requesterId },
});
if (requester.role !== "admin") {
return NextResponse.json({ error: "Unauthorized" }, { status: 403 });
}
// Proceed with deletion
await db.users.delete({ where: { id: userId } });
}
-- Enable RLS on all tables
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Users can only view their own data
CREATE POLICY "Users view own data"
ON users FOR SELECT
USING (auth.uid() = id);
-- Users can only update their own data
CREATE POLICY "Users update own data"
ON users FOR UPDATE
USING (auth.uid() = id);
import DOMPurify from 'isomorphic-dompurify'
// ALWAYS sanitize user-provided HTML
function renderUserContent(html: string) {
const clean = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'],
ALLOWED_ATTR: []
})
return <div dangerouslySetInnerHTML={{ __html: clean }} />
}
// next.config.js
const securityHeaders = [
{
key: "Content-Security-Policy",
value: `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
`
.replace(/\s{2,}/g, " ")
.trim(),
},
];
import { csrf } from "@/lib/csrf";
export async function POST(request: Request) {
const token = request.headers.get("X-CSRF-Token");
if (!csrf.verify(token)) {
return NextResponse.json({ error: "Invalid CSRF token" }, { status: 403 });
}
// Process request
}
res.setHeader(
"Set-Cookie",
`session=${sessionId}; HttpOnly; Secure; SameSite=Strict`,
);
import rateLimit from "express-rate-limit";
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: "Too many requests",
});
// Apply to routes
app.use("/api/", limiter);
// Aggressive rate limiting for searches
const searchLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 10, // 10 requests per minute
message: "Too many search requests",
});
app.use("/api/search", searchLimiter);
// ❌ WRONG: Logging sensitive data
console.log("User login:", { email, password });
console.log("Payment:", { cardNumber, cvv });
// ✅ CORRECT: Redact sensitive data
console.log("User login:", { email, userId });
console.log("Payment:", { last4: card.last4, userId });
// ❌ WRONG: Exposing internal details
catch (error) {
return NextResponse.json(
{ error: error.message, stack: error.stack },
{ status: 500 }
)
}
// ✅ CORRECT: Generic error messages
catch (error) {
console.error('Internal error:', error)
return NextResponse.json(
{ error: 'An error occurred. Please try again.' },
{ status: 500 }
)
}
import { verify } from "@solana/web3.js";
async function verifyWalletOwnership(
publicKey: string,
signature: string,
message: string,
) {
try {
const isValid = verify(
Buffer.from(message),
Buffer.from(signature, "base64"),
Buffer.from(publicKey, "base64"),
);
return isValid;
} catch (error) {
return false;
}
}
async function verifyTransaction(transaction: Transaction) {
// Verify recipient
if (transaction.to !== expectedRecipient) {
throw new Error("Invalid recipient");
}
// Verify amount
if (transaction.amount > maxAmount) {
throw new Error("Amount exceeds limit");
}
// Verify user has sufficient balance
const balance = await getBalance(transaction.from);
if (balance < transaction.amount) {
throw new Error("Insufficient balance");
}
return true;
}
# Check for vulnerabilities
npm audit
# Fix automatically fixable issues
npm audit fix
# Update dependencies
npm update
# Check for outdated packages
npm outdated
# ALWAYS commit lock files
git add package-lock.json
# Use in CI/CD for reproducible builds
npm ci # Instead of npm install
// Test authentication
test("requires authentication", async () => {
const response = await fetch("/api/protected");
expect(response.status).toBe(401);
});
// Test authorization
test("requires admin role", async () => {
const response = await fetch("/api/admin", {
headers: { Authorization: `Bearer ${userToken}` },
});
expect(response.status).toBe(403);
});
// Test input validation
test("rejects invalid input", async () => {
const response = await fetch("/api/users", {
method: "POST",
body: JSON.stringify({ email: "not-an-email" }),
});
expect(response.status).toBe(400);
});
// Test rate limiting
test("enforces rate limits", async () => {
const requests = Array(101)
.fill(null)
.map(() => fetch("/api/endpoint"));
const responses = await Promise.all(requests);
const tooManyRequests = responses.filter((r) => r.status === 429);
expect(tooManyRequests.length).toBeGreaterThan(0);
});
development
Review recently changed code with three separate read-only agents for reuse, quality, and efficiency, then return prioritized issue lists. Use after implementing changes, before verification or commit, or when the user asks to simplify, clean up, reduce duplication, or review recent changes.
development
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
development
A checklist of post-work verification steps. Use proactively after completing a feature or significant code change; before creating a PR; when you want to ensure quality gates pass or after refactoring. Do NOT run for documentation-only changes.
development
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.