security-review
Skill1 starsChanged 8 months agoApache-2.0View on GitHub
Reviews code for security flaws and hardens applications, covering OWASP Top 10 risks, injection (SQL, XSS, command), authentication and authorization, secrets handling and rotation, dependency scanning, input validation, CORS, CSRF, rate limiting and security headers, with examples in JavaScript, Python and Go. Use when reviewing a diff or file for vulnerabilities, hardening login or session code, setting up headers, CORS or rate limits, or auditing how secrets and dependencies are handled.
- Reads credentials
We split this skill into the rules it gives an agent
8 rules. 0 are common, 7 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 167 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 123
Never store JWTs in localStorage (XSS-accessible).
- Distinctive: line 124
Never put sensitive data in JWT payload (it's base64, not encrypted).
- Very specific: line 125
Always validate the alg header server-side.
- Distinctive: line 162
IDOR prevention: Always check that the authenticated user owns or has permission to access the resource identified by the URL parameter.
- Distinctive: line 183
Runtime secrets: Use environment variables or a secrets manager (AWS SSM, Vault, Doppler).
- Distinctive: line 196
Add new secret to secrets manager
- Distinctive: line 198
Update clients to use new secret
- Distinctive: line 199
Remove old secret after grace period (24-48 hours)
“Common” is measured: kept by at least 6 in 10 of the 167 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
You are a security engineer specializing in application security, code review, and vulnerability prevention across web, API, and systems code.
Use this skill when
- Reviewing code for security vulnerabilities
- Hardening authentication, authorization, or input handling
- Setting up security headers, CORS, CSRF protection
- Configuring dependency scanning or secrets management
- Designing rate limiting or abuse prevention
OWASP Top 10 Quick Reference (2021 edition)
The 2025 edition reorders this list: it adds software supply chain failures and mishandling of exceptional conditions, and folds SSRF into broken access control. The defenses below still apply. Check owasp.org/Top10 for the current numbering before you cite an A-number in a report.
| # | Vulnerability | Primary Defense |
| A01 | Broken Access Control | Deny by default, server-side checks on every request |
| A02 | Cryptographic Failures | TLS everywhere, bcrypt/argon2 for passwords, no secrets in code |
| A03 | Injection | Parameterized queries, context-aware output encoding |
| A04 | Insecure Design | Threat modeling, secure defaults, least privilege |
| A05 | Security Misconfiguration | Minimal installs, disable defaults, automate config |
| A06 | Vulnerable Components | SCA scanning (dependabot/snyk), pin versions, update regularly |
| A07 | Auth Failures | MFA, credential stuffing protection, secure session management |
| A08 | Data Integrity Failures | Verify signatures, use SRI, secure CI/CD |
| A09 | Logging Failures | Log security events, don't log secrets, monitor alerts |
| A10 | SSRF | Allowlist outbound hosts, validate/sanitize URLs |
Injection Prevention
SQL Injection
# BAD: string concatenation
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# GOOD: parameterized query
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
# GOOD: ORM (SQLAlchemy)
user = session.query(User).filter(User.id == user_id).first()// BAD: template literal in query
db.query(`SELECT * FROM users WHERE email = '${email}'`);
// GOOD: parameterized
db.query("SELECT * FROM users WHERE email = $1", [email]);// BAD: fmt.Sprintf in query
db.Query(fmt.Sprintf("SELECT * FROM users WHERE id = %d", id))
// GOOD: parameterized
db.Query("SELECT * FROM users WHERE id = $1", id)XSS Prevention
// BAD: innerHTML with user data
element.innerHTML = userInput;
// GOOD: textContent (no HTML parsing)
element.textContent = userInput;
// React: NEVER use dangerouslySetInnerHTML with user data
// If you must render HTML, sanitize with DOMPurify:
import DOMPurify from "dompurify";
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(html) }} />
// CSP header to block inline scripts:
// Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'Command Injection
# BAD: shell=True with user input
subprocess.run(f"convert {filename} output.png", shell=True)
# GOOD: pass args as list, no shell
subprocess.run(["convert", filename, "output.png"], shell=False)
# GOOD: validate input against allowlist
ALLOWED = re.compile(r'^[a-zA-Z0-9_\-]+\.png$')
if not ALLOWED.match(filename):
raise ValueError("Invalid filename")Authentication Patterns
Password Hashing
# Use argon2 (preferred) or bcrypt. NEVER MD5/SHA for passwords.
from argon2 import PasswordHasher
ph = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=4)
hash = ph.hash(password)
ph.verify(hash, password) # raises on mismatchJWT Best Practices
// Sign with RS256 (asymmetric) for services, HS256 for simple apps
const token = jwt.sign(
{ sub: user.id, role: user.role },
privateKey,
{ algorithm: "RS256", expiresIn: "15m" } // short-lived access tokens
);
// ALWAYS validate: algorithm, expiration, issuer, audience
const payload = jwt.verify(token, publicKey, {
algorithms: ["RS256"], // prevent algorithm confusion attack
issuer: "myapp",
audience: "myapp-api",
});JWT rules:
- Access tokens: 15 min max. Refresh tokens: days, stored server-side, rotatable.
- Never store JWTs in localStorage (XSS-accessible). Use httpOnly, Secure, SameSite=Strict cookies.
- Never put sensitive data in JWT payload (it's base64, not encrypted).
- Always validate the
algheader server-side. Rejectnonealgorithm.
Session Security
// Express session config
app.use(session({
secret: process.env.SESSION_SECRET, // 32+ random bytes
name: "__Host-sid", // __Host- prefix enforces Secure + no Domain
cookie: {
httpOnly: true,
secure: true,
sameSite: "strict",
maxAge: 3600000, // 1 hour
},
resave: false,
saveUninitialized: false,
}));Authorization
Principle: deny by default, check on every request, server-side only.
# BAD: checking permissions client-side only
# BAD: checking only "is authenticated" without role/ownership check
# GOOD: middleware that checks ownership
async def get_document(request: Request, doc_id: int) -> Document:
doc = await db.get_document(doc_id)
if doc is None:
raise HTTPException(404) # don't reveal existence
if doc.owner_id != request.user.id and request.user.role != "admin":
raise HTTPException(404) # 404 not 403 to prevent enumeration
return docIDOR prevention: Always check that the authenticated user owns or has permission to access the resource identified by the URL parameter. Never trust client-supplied IDs without ownership verification.
Secrets Management
# NEVER commit secrets. Use .gitignore + pre-commit scanning.
# .gitignore
.env
*.pem
*.key
credentials.json
# Pre-commit: gitleaks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaksRuntime secrets: Use environment variables or a secrets manager (AWS SSM, Vault, Doppler). Never hardcode. Never log secrets. Rotate regularly.
Secrets Rotation
Rotation schedule:
- API keys: Every 90 days
- Database passwords: Every 90 days or on personnel changes
- JWT signing keys: Every 6-12 months
- TLS certificates: Automated via Let's Encrypt (90-day expiry)
- Service account tokens: Every 30-90 days
Rotation process:
- Generate new secret (key/password/token)
- Add new secret to secrets manager
- Deploy code that supports BOTH old and new secrets
- Update clients to use new secret
- Remove old secret after grace period (24-48 hours)
# Example: rotate a database password with zero downtime.
# Keep two roles with identical grants (myapp_a, myapp_b). Only one is live.
# Changing the live role's password would break running instances at once.
# 1. Generate the new password and set it on the idle role (myapp_b).
# Pipe the SQL through stdin so the password never shows in the process list.
NEW_PASS=$(openssl rand -base64 32)
printf "ALTER ROLE myapp_b PASSWORD '%s';\n" "$NEW_PASS" | psql "$ADMIN_DATABASE_URL"
# 2. Store it encrypted (SecureString), not as a plain String parameter
aws ssm put-parameter --name /prod/db/password --type SecureString --value "$NEW_PASS" --overwrite
unset NEW_PASS
# 3. Rolling restart so instances pick up the new role and password
kubectl rollout restart deployment/myapp
kubectl rollout status deployment/myapp
# 4. After every instance is on myapp_b and the grace period has passed,
# disable login for the old role (myapp_a). Next rotation swaps the roles.# GOOD: secrets from environment with validation
import os
def get_required_env(key: str) -> str:
value = os.environ.get(key)
if not value:
raise RuntimeError(f"Required env var {key} is not set")
return value
DATABASE_URL = get_required_env("DATABASE_URL")Security Headers
# Nginx or reverse proxy
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.example.com" always;CORS Configuration
// BAD: allow everything
app.use(cors({ origin: "*", credentials: true })); // credentials + wildcard = browser rejects
// GOOD: explicit allowlist
app.use(cors({
origin: ["https://myapp.com", "https://staging.myapp.com"],
methods: ["GET", "POST", "PUT", "DELETE"],
allowedHeaders: ["Content-Type", "Authorization"],
credentials: true,
maxAge: 86400,
}));CSRF Protection
For cookie-based auth (sessions), use the synchronizer token pattern or SameSite cookies:
// Option 1: SameSite=Strict cookies (sufficient for most apps)
// Option 2: CSRF token (needed if SameSite=Lax or cross-subdomain)
// Modern approach: csrf-csrf (csurf is deprecated)
import { doubleCsrf } from "csrf-csrf";
const { generateToken, doubleCsrfProtection } = doubleCsrf({
getSecret: () => process.env.CSRF_SECRET,
cookieName: "__Host-csrf",
cookieOptions: { httpOnly: true, secure: true, sameSite: "strict" },
getTokenFromRequest: (req) => req.headers["x-csrf-token"],
});
app.use(doubleCsrfProtection);
// Alternative: Double-submit cookie pattern (manual)
app.post("/api/action", (req, res) => {
const tokenFromCookie = req.cookies.csrfToken;
const tokenFromHeader = req.headers["x-csrf-token"];
if (tokenFromCookie !== tokenFromHeader) return res.status(403).send("CSRF validation failed");
// Process request
});Token-based auth (Bearer JWT in Authorization header) is inherently CSRF-safe because browsers don't auto-attach it.
Rate Limiting
// Express rate limiting
import rateLimit from "express-rate-limit";
// General API rate limit
app.use("/api/", rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
limit: 100,
standardHeaders: true,
legacyHeaders: false,
keyGenerator: (req) => req.ip, // or req.user?.id for authenticated
}));
// Strict limit on auth endpoints
app.use("/api/auth/", rateLimit({
windowMs: 15 * 60 * 1000,
limit: 5, // 5 login attempts per 15 min
skipSuccessfulRequests: true, // don't count successful logins
}));Dependency Scanning
# JavaScript: npm audit + Snyk
npm audit --omit=dev
npx snyk test
# Python: pip-audit
pip-audit
# Go: govulncheck (official)
govulncheck ./...
# CI: GitHub Dependabot + CodeQL
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10Input Validation Checklist
- Validate on the server. Client-side validation is UX, not security.
- Allowlist over denylist. Define what IS valid, not what isn't.
- Validate type, length, range, and format for every input field.
- Reject unexpected fields (strict schema parsing with Pydantic/Zod).
- Sanitize for output context (HTML encode for HTML, SQL parameterize for SQL).
- File uploads: validate MIME type by content (not extension), limit size, store outside webroot, randomize filenames.
- URLs: validate scheme (https only), resolve and check against SSRF allowlist.
Other versions192 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 192
- affaan-m/ECC★ 246ksame name
- github/awesome-copilot★ 41ksame name
- langfuse/langfuse★ 37ksame name
- nearai/ironclaw★ 13ksame name
- joe-bell/cva★ 6.9ksame name
- doorkeeper-gem/doorkeeper★ 5.5ksame name
- compozy/compozy★ 2.8ksame name
- getsentry/sentry-python★ 2.2ksame name
- trycompai/comp★ 2ksame name
- xu-xiang/everything-claude-code-zh★ 1.9ksame name
182 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Used alongsideProjects with it also use dependency-cve-sweep, fleet-standard-adoption and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
berntpoppSkilldependency-cve-sweep
Use when handling Dependabot PRs, CodeQL/Trivy alerts, or doing a routine dependency/CVE sweep for this repo.
Also in 12 projects that use this
berntpoppSkillfleet-standard-adoption
Use when bringing this repo into compliance with a GeneFoundry fleet standard (tool-naming, response-envelope, container-hardening, versioning, MCP transport, or logging) or closing its tracking issue.
Also in 12 projects that use this
niloykumarbarmanSkillagent-sort
Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.
Also in 12 projects that use this
ysyecustSkillbrand-discovery
Use when a brand needs to discover or articulate its identity through structured multi-session interviews. Covers purpose, positioning, audience, personality, voice, narrative, and founder-brand tension across 8 modules using laddering, 5 Whys, and projective techniques. Produces a resumable session with disk-persisted state and a master brandbook (90_SYNTHESIS.md).
Also in 5 projects that use this
InfopibeSkilleverything-claude-code
Also in 11 projects that use this
junimnjwSkillralphinho-rfc-pipeline
RFC-driven multi-agent DAG execution pattern with quality gates, merge queues, and work unit orchestration.
Also in 10 projects that use this
- +2 more from berntpopp
In this repository21 other files it gives its agents.
- accessibility-wcagSkill
- api-designSkill
- bugbounty-reportSkill
- ci-cd-pipelinesSkill
- codebase-analysisSkill
- database-designSkill
- design-docSkill
- docker-kubernetesSkill
- git-workflowSkill
- go-devSkill
- i18n-localizationSkill
- llm-integrationSkill
- nextjs-16Skill
- oauth-authSkill
- performance-optimizationSkill
- python-best-practicesSkill
- scraping-automationSkill
- seo-metaSkill
- tailwind-cssSkill
- testingSkill
- ts-devSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

