Grey Haven's security best practices - input validation, output sanitization, multi-tenant RLS, secret management with Doppler, rate limiting, OWASP Top 10 for TanStack/FastAPI stack. Use when implementing security-critical features.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Instruções da origem · Visualização somente leitura
name
grey-haven-security-practices
description
Grey Haven's security best practices - input validation, output sanitization, multi-tenant RLS, secret management with Doppler, rate limiting, OWASP Top 10 for TanStack/FastAPI stack. Use when implementing security-critical features.
// [OK] Correct - Use process.env (Doppler provides at runtime)const apiKey = process.env.OPENAI_API_KEY!;
// [X] Wrong - Hardcoded secretsconst apiKey = "sk-..."; // NEVER DO THIS!
# [OK] Correct - Use os.getenv (Doppler provides at runtime)import os
api_key = os.getenv("OPENAI_API_KEY")
# [X] Wrong - Hardcoded secrets
api_key = "sk-..."# NEVER DO THIS!
Input Validation
TypeScript (Zod Validation)
import { z } from"zod";
// [OK] Validate all user inputconstUserCreateSchema = z.object({
email_address: z.string().email().max(255),
name: z.string().min(1).max(100),
age: z.number().int().min(0).max(150),
});
exportconst createUser = createServerFn("POST", async (data: unknown) => {
// Validate inputconst validated = UserCreateSchema.parse(data);
// Now safe to useawait db.insert(users).values(validated);
});
Python (Pydantic Validation)
from pydantic import BaseModel, EmailStr, Field, validator
classUserCreate(BaseModel):
"""User creation schema with validation."""
email_address: EmailStr
name: str = Field(min_length=1, max_length=100)
age: int = Field(ge=0, le=150)
@validator("name")defname_must_not_contain_special_chars(cls, v):
ifnot v.replace(" ", "").isalnum():
raise ValueError("Name must be alphanumeric")
return v
@router.post("/users", response_model=UserResponse)asyncdefcreate_user(data: UserCreate):
# Pydantic validates automatically# data is now safe to usepass
Output Sanitization
HTML Escaping (XSS Prevention)
// [OK] React automatically escapes in JSXfunctionUserProfile({ user }: { user: User }) {
return<div>{user.name}</div>; // Safe, auto-escaped
}
// [X] Dangerous - Raw HTMLfunctionUserProfile({ user }: { user: User }) {
return<divdangerouslySetInnerHTML={{__html:user.bio }} />; // UNSAFE!
}
// [OK] If HTML needed, sanitize firstimportDOMPurifyfrom"isomorphic-dompurify";
functionUserProfile({ user }: { user: User }) {
const sanitized = DOMPurify.sanitize(user.bio);
return<divdangerouslySetInnerHTML={{__html:sanitized }} />;
}
SQL Injection Prevention
// [OK] Use parameterized queries (Drizzle)const user = await db.query.users.findFirst({
where: eq(users.email_address, email), // Safe, parameterized
});
// [X] Never concatenate SQLconst user = await db.execute(
`SELECT * FROM users WHERE email = '${email}'`// SQL INJECTION!
);
# [OK] Use ORM (SQLModel/SQLAlchemy)
user = await session.execute(
select(User).where(User.email_address == email) # Safe, parameterized
)
# [X] Never concatenate SQL
user = await session.execute(
f"SELECT * FROM users WHERE email = '{email}'"# SQL INJECTION!
)
Multi-Tenant Security (RLS)
Enable RLS on All Tables
-- ALWAYS enable RLS for multi-tenant tablesALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
ALTER TABLE teams ENABLE ROW LEVEL SECURITY;
Tenant Isolation Policies
-- Authenticated users see only their tenant's dataCREATE POLICY "Tenant isolation for users"
ON users FORALLTO authenticated
USING (tenant_id = (current_setting('request.jwt.claims')::json->>'tenant_id')::uuid);