shared-security-auth-security
Secrets management, XSS prevention, CSRF protection, dependency scanning, DOMPurify sanitization, CSP headers, CODEOWNERS, HttpOnly cookies
Install
npx skills add https://github.com/agents-inc/skills/tree/main/dist/plugins/shared-security-auth-security/skills/shared-security-auth-security
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install agents-inc-skills@llmmart
git clone https://github.com/agents-inc/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole agents-inc/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Security Patterns
Quick Guide: Managing secrets? Use .env.local (gitignored), CI secrets, rotate on compromise or team changes. Dependency security? Enable automated scanning (Dependabot), patch critical vulns within 24hrs. XSS prevention? Modern frameworks auto-escape output by default - never bypass with raw HTML injection unless sanitized with DOMPurify. Set CSP headers. CODEOWNERS? Require security team review for auth/, .env.example, workflows.
Detailed Resources:
- For code examples, see examples/core.md (essential patterns)
- For decision frameworks and anti-patterns, see reference.md
Additional Examples:
- examples/xss-prevention.md - XSS protection, DOMPurify, CSP headers
- examples/dependency-security.md - Dependabot, CI security checks
- examples/access-control.md - CODEOWNERS, rate limiting, branch protection
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST NEVER commit secrets to the repository - use .env.local and CI secrets only)
(You MUST sanitize ALL user input before rendering raw HTML - use DOMPurify before any HTML injection)
(You MUST patch critical/high vulnerabilities within 24 hours - use Dependabot for automated scanning)
(You MUST use HttpOnly cookies for authentication tokens - NEVER localStorage or sessionStorage)
(You MUST configure CODEOWNERS for security-sensitive files - require security team approval)
</critical_requirements>
Auto-detection: security, secrets management, XSS prevention, CSRF protection, Dependabot, vulnerability scanning, authentication, DOMPurify, CSP headers, CODEOWNERS, HttpOnly cookies
When to use:
- Managing secrets securely (never commit, use .env.local and CI secrets)
- Setting up Dependabot for automated vulnerability scanning
- Preventing XSS attacks (framework auto-escaping, DOMPurify, CSP headers)
- Configuring CODEOWNERS for security-sensitive code
- Implementing secure authentication and token storage
When NOT to use:
- For general code quality reviews (not a security concern)
- For performance optimization (different domain)
- For CI/CD pipeline setup (security patterns here are for code, not infrastructure)
- When security review would delay critical hotfixes (document for follow-up)
Key patterns covered:
- Never commit secrets (.gitignore, CI secrets, rotation policies quarterly)
- Automated dependency scanning with Dependabot (critical within 24h)
- XSS prevention (framework auto-escaping, DOMPurify for HTML, CSP headers)
- CSRF protection with tokens and SameSite cookies
- CODEOWNERS for security-sensitive areas (.env.example, auth code, workflows)
- Secure token storage (HttpOnly cookies, in-memory access tokens)
Defense in depth layers:
- Secrets: .env.local (dev) -> CI secrets -> Environment variables (production)
- XSS: Framework auto-escaping -> DOMPurify sanitization -> CSP headers
- CSRF: Tokens -> SameSite cookies -> Server-side validation
- Dependencies: Automated scanning -> CI security audit -> Manual review
<red_flags>
RED FLAGS
High Priority Issues:
- Committing secrets to repository (.env files, API keys in code)
- Injecting raw HTML with unsanitized user input (enables XSS attacks)
- Storing authentication tokens in localStorage/sessionStorage (accessible to XSS)
- No CSRF protection on state-changing operations (allows forged requests)
- Critical/high vulnerabilities unpatched (exploit window open)
Medium Priority Issues:
- No Dependabot configuration (manual vulnerability detection only)
- Missing CODEOWNERS for security-sensitive files (no automatic review)
- No CSP headers configured (no script execution controls)
- Individual CODEOWNERS instead of teams (single point of failure)
- Trusting client-side validation only (easily bypassed)
- Exposing internal error details to users (information leakage)
Gotchas & Edge Cases:
.env.localis gitignored by default in some frameworks but not all - verify your.gitignore- DOMPurify's default config allows
<style>and<form>tags - use explicit whitelist - SameSite=Strict blocks legitimate cross-site requests - use Lax for general session cookies
- CSP nonces must be unique per request - generate fresh nonces server-side
- X-XSS-Protection header is deprecated - set to "0" or omit, use CSP instead
See reference.md for common mistakes, anti-patterns with code examples, and decision frameworks.
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md
(You MUST NEVER commit secrets to the repository - use .env.local and CI secrets only)
(You MUST sanitize ALL user input before rendering raw HTML - use DOMPurify before any HTML injection)
(You MUST patch critical/high vulnerabilities within 24 hours - use Dependabot for automated scanning)
(You MUST use HttpOnly cookies for authentication tokens - NEVER localStorage or sessionStorage)
(You MUST configure CODEOWNERS for security-sensitive files - require security team approval)
Failure to follow these rules will create security vulnerabilities enabling XSS attacks, token theft, CSRF attacks, and data breaches.
</critical_reminders>
Files (skills)
-
examples
-
access-control.md 5.5 KB
# Security Patterns - Access Control Examples > CODEOWNERS, branch protection, and rate limiting patterns. See [SKILL.md](../SKILL.md) for core concepts and [reference.md](../reference.md) for decision frameworks. **Related Examples:** - [core.md](core.md) - Essential patterns (secrets, CSRF, cookies) - [xss-prevention.md](xss-prevention.md) - XSS protection, DOMPurify, CSP headers - [dependency-security.md](dependency-security.md) - Dependabot, CI security checks --- ## Pattern 1: Code Ownership (CODEOWNERS) ### Good Example - CODEOWNERS Configuration ``` # .github/CODEOWNERS # Global owners (fallback) * @tech-leads # Security-sensitive files require security team approval .env.example @security-team @tech-leads .github/workflows/* @devops-team @security-team apps/*/env.ts @security-team @backend-team packages/auth/* @security-team @backend-team # Frontend patterns require frontend team review .claude/* @frontend-team src/skillsNew/* @frontend-team @tech-leads # Backend packages packages/api/* @backend-team packages/database/* @backend-team @dba-team # Build and infrastructure turbo.json @devops-team @tech-leads package.json @tech-leads .github/dependabot.yml @devops-team @security-team Dockerfile @devops-team # Critical business logic apps/*/features/payment/* @backend-team @security-team @product-team apps/*/features/auth/* @security-team @backend-team # Design system packages/ui/* @frontend-team @design-team ``` **Why good:** Automatic reviewer assignment ensures expertise reviews critical changes, prevents unauthorized changes to security-sensitive code, creates audit trail for security decisions, teams provide better coverage than individual reviewers ### Bad Example - No CODEOWNERS or Individual Owners ``` # BAD: No CODEOWNERS # No automatic reviewer assignment # Anyone can modify security-sensitive files # No audit trail for critical changes # BAD: Individual owners .env.example @john-developer packages/auth/* @jane-engineer ``` **Why bad:** Missing CODEOWNERS allows unauthorized changes to critical code, individual owners create single points of failure during vacations/departures, no automatic assignment leads to missed security reviews, lack of audit trail makes incident investigation difficult --- ## Pattern 2: Branch Protection Configuration ### Good Example - Branch Protection Configuration ```jsonc // Branch protection configuration (via GitHub API or UI settings) { "required_pull_request_reviews": { "required_approving_review_count": 2, "require_code_owner_reviews": true, "dismiss_stale_reviews": true, }, "required_status_checks": { "strict": true, "contexts": ["ci/test", "ci/lint", "ci/type-check", "ci/security-audit"], }, "enforce_admins": true, "restrictions": null, } ``` **Why good:** Enforces code owner approval preventing bypass of security reviews, required status checks ensure tests and security audits pass, dismiss_stale_reviews prevents outdated approvals, enforce_admins applies rules even to repository administrators --- ## Pattern 3: Rate Limiting ### Good Example - Client-Side Rate Limiting ```typescript const MAX_REQUESTS_PER_WINDOW = 100; const RATE_LIMIT_WINDOW_MS = 60000; // 1 minute class RateLimitedClient { private queue: Array<() => Promise<any>> = []; private processing = false; private requestsInWindow = 0; private windowStart = Date.now(); constructor( private maxRequests: number, private windowMs: number, ) {} async request<T>(url: string, options?: RequestInit): Promise<T> { return new Promise((resolve, reject) => { this.queue.push(async () => { try { await this.waitForRateLimit(); const response = await fetch(url, options); resolve(await response.json()); } catch (error) { reject(error); } }); this.processQueue(); }); } private async waitForRateLimit() { const now = Date.now(); const elapsed = now - this.windowStart; if (elapsed >= this.windowMs) { this.requestsInWindow = 0; this.windowStart = now; } if (this.requestsInWindow >= this.maxRequests) { const waitTime = this.windowMs - elapsed; await new Promise((resolve) => setTimeout(resolve, waitTime)); this.requestsInWindow = 0; this.windowStart = Date.now(); } this.requestsInWindow++; } private async processQueue() { if (this.processing || this.queue.length === 0) return; this.processing = true; while (this.queue.length > 0) { const request = this.queue.shift()!; await request(); } this.processing = false; } } // Usage const api = new RateLimitedClient( MAX_REQUESTS_PER_WINDOW, RATE_LIMIT_WINDOW_MS, ); ``` **Why good:** Prevents hitting server rate limits and getting 429 errors, queuing provides better UX than failing requests, named constants make rate limit policy auditable, sliding window prevents burst requests ### Bad Example - No Rate Limiting ```typescript // BAD: No rate limiting async function sendMessage(message: string) { return fetch("/api/messages", { method: "POST", body: JSON.stringify({ message }), }); } // BAD: Magic numbers if (this.requestsInWindow >= 100) { // What's the policy? await new Promise((resolve) => setTimeout(resolve, 60000)); // Why 60 seconds? } ``` **Why bad:** No rate limiting allows rapid-fire requests that overwhelm servers, users receive 429 errors with poor UX, magic numbers obscure rate limit policy, no queuing means requests fail instead of being delayed -
core.md 5.8 KB
# Security Patterns - Core Examples > Essential security patterns. See [SKILL.md](../SKILL.md) for core concepts and [reference.md](../reference.md) for decision frameworks. **Additional Examples:** - [xss-prevention.md](xss-prevention.md) - XSS protection, DOMPurify, CSP headers - [dependency-security.md](dependency-security.md) - Dependabot, CI security checks - [access-control.md](access-control.md) - CODEOWNERS, rate limiting, branch protection --- ## Pattern 1: Secret Management ### Rotation Policy Constants ```typescript // NIST SP 800-63-4 (2025): Avoid mandatory periodic rotation for user passwords. // Use event-based rotation (on compromise) instead. // Periodic rotation is still recommended for service/privileged accounts. const ROTATION_SERVICE_ACCOUNT_DAYS = 90; // Quarterly for service accounts const ROTATION_PRIVILEGED_ACCOUNT_DAYS = 90; // Quarterly for privileged access const ROTATION_API_KEYS_DAYS = 365; // Annually or on compromise const CERT_EXPIRY_WARNING_DAYS = 30; // 30 days notice before expiry // User passwords: rotate on compromise only (NIST 2025 guidance) ``` ### Good Example - Secure Token Storage ```typescript // Frontend: Don't store token at all // Backend sets: Set-Cookie: token=xxx; HttpOnly; Secure; SameSite=Strict // In-memory access token - cleared on tab close let accessToken: string | null = null; export function setAccessToken(token: string) { accessToken = token; // In-memory only, lost on refresh } export function getAccessToken() { return accessToken; } // Auto-refresh pattern: intercept 401 responses to transparently refresh tokens // Implementation depends on your HTTP client (fetch wrapper, interceptors, etc.) async function handleUnauthorized(failedRequest: Request): Promise<Response> { const newToken = await refreshAccessToken(); // Uses HttpOnly cookie setAccessToken(newToken); return fetch(failedRequest); // Retry with new token } ``` **Why good:** HttpOnly cookies inaccessible to JavaScript prevents XSS token theft, in-memory tokens cleared on tab close, automatic refresh maintains user session without exposing credentials ### Bad Example - Storing Tokens in localStorage ```typescript // BAD: Storing tokens in localStorage function storeAuthToken(token: string) { localStorage.setItem("authToken", token); } // BAD: Committing secrets const API_KEY = "sk_live_1234567890abcdef"; // NEVER do this ``` **Why bad:** localStorage accessible to any JavaScript including XSS attacks, tokens persist indefinitely enabling session hijacking, committed secrets exposed in git history forever even after deletion **When to use:** Always use HttpOnly cookies for authentication tokens, environment variables for API keys and secrets, secret rotation for all credentials quarterly or on team changes. **When not to use:** Never store authentication tokens in localStorage/sessionStorage, never commit secrets to repository, never hardcode credentials in source code. --- ## Pattern 2: CSRF Protection ### Good Example - CSRF Token with Request Interceptor ```typescript const CSRF_TOKEN_META_NAME = "csrf-token"; const CSRF_HEADER_NAME = "X-CSRF-Token"; // Centralized CSRF token injection - apply via your HTTP client's interceptor/middleware function getCsrfToken(): string | undefined { return document.querySelector<HTMLMetaElement>( `meta[name="${CSRF_TOKEN_META_NAME}"]`, )?.content; } // Wrap fetch (or use your HTTP client's interceptor) to auto-inject CSRF token async function secureFetch( url: string, options: RequestInit = {}, ): Promise<Response> { const token = getCsrfToken(); const headers = new Headers(options.headers); if (token) { headers.set(CSRF_HEADER_NAME, token); } return fetch(url, { ...options, headers, credentials: "include" }); } export { secureFetch }; ``` **Why good:** Centralized interceptor automatically adds CSRF token to all requests preventing manual errors, credentials: "include" enables cookie-based authentication, named constants make token source and header name auditable, single wrapper ensures consistency across the application ### Bad Example - No CSRF Protection ```typescript // BAD: No CSRF protection on state-changing request async function updateProfile(data: ProfileData) { return fetch("/api/profile", { method: "PUT", body: JSON.stringify(data), }); } // BAD: Manual token per request - easy to forget async function badUpdate(data: ProfileData) { const token = document.querySelector('meta[name="csrf-token"]')?.content; return fetch("/api/profile", { method: "PUT", headers: { "X-CSRF-Token": token! }, // Easy to forget, non-null assertion unsafe body: JSON.stringify(data), }); } ``` **Why bad:** Missing CSRF protection allows attackers to forge requests from other sites, manual token addition per request is error-prone and often forgotten, magic string selectors obscure security mechanism, non-null assertion (token!) can fail at runtime if token missing ### Good Example - Cookie Security ```typescript // Backend cookie configuration const COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 7; // 7 days res.cookie("authToken", token, { httpOnly: true, // Prevents JavaScript access secure: true, // HTTPS only sameSite: "lax", // Modern default - balances security and UX (use 'strict' for sensitive operations only) maxAge: COOKIE_MAX_AGE_SECONDS * 1000, path: "/", }); ``` **Why good:** HttpOnly prevents XSS token theft via JavaScript, Secure ensures cookies only sent over HTTPS preventing interception, SameSite=Lax is the modern browser default providing CSRF protection while allowing legitimate cross-site navigation, named constant makes expiration policy clear and auditable > **Note:** Use `sameSite: 'strict'` only for cookies used in sensitive state-changing operations. For general session cookies, `'lax'` provides better UX while maintaining security. -
dependency-security.md 4.5 KB
# Security Patterns - Dependency Security Examples > Automated vulnerability scanning with Dependabot and CI security checks. See [SKILL.md](../SKILL.md) for core concepts and [reference.md](../reference.md) for decision frameworks. **Related Examples:** - [core.md](core.md) - Essential patterns (secrets, CSRF, cookies) - [xss-prevention.md](xss-prevention.md) - XSS protection, DOMPurify, CSP headers - [access-control.md](access-control.md) - CODEOWNERS, rate limiting, branch protection --- ## Pattern 1: Dependabot Configuration ### Good Example - Dependabot Configuration ```yaml # .github/dependabot.yml version: 2 updates: # Enable version updates for npm - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" day: "monday" time: "09:00" open-pull-requests-limit: 10 reviewers: - "security-team" assignees: - "tech-lead" # Group non-security updates groups: development-dependencies: dependency-type: "development" update-types: - "minor" - "patch" production-dependencies: dependency-type: "production" update-types: - "patch" # Auto-merge patch updates if tests pass allow: - dependency-type: "all" # Ignore specific packages if needed ignore: - dependency-name: "eslint" versions: - ">= 9.0.0" # GitHub Actions security updates - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" ``` **Why good:** Automated security updates reduce manual work, weekly scans catch vulnerabilities early, grouped updates reduce PR noise, reviewer assignment ensures expertise reviews changes ### Bad Example - No Dependabot Configuration ```yaml # BAD: No Dependabot configuration # No automated security scanning # Manual dependency updates only # Vulnerabilities go unnoticed ``` **Why bad:** Manual dependency updates are error-prone and often forgotten, vulnerabilities remain unpatched for weeks or months, no visibility into security issues, increased risk of exploitation --- ## Pattern 2: CI Security Checks ### Good Example - CI Security Checks ```typescript // scripts/security-check.ts import { exec } from "child_process"; import { promisify } from "util"; const execAsync = promisify(exec); const CRITICAL_THRESHOLD = 0; const HIGH_THRESHOLD = 0; interface AuditResult { vulnerabilities: { info: number; low: number; moderate: number; high: number; critical: number; }; } async function runSecurityAudit() { try { console.log("Running security audit..."); const { stdout } = await execAsync("bun audit --json"); const result: AuditResult = JSON.parse(stdout); const { vulnerabilities } = result; const total = vulnerabilities.info + vulnerabilities.low + vulnerabilities.moderate + vulnerabilities.high + vulnerabilities.critical; console.log("\nSecurity Audit Results:"); console.log(` Critical: ${vulnerabilities.critical}`); console.log(` High: ${vulnerabilities.high}`); console.log(` Moderate: ${vulnerabilities.moderate}`); console.log(` Low: ${vulnerabilities.low}`); console.log(` Info: ${vulnerabilities.info}`); console.log(` Total: ${total}\n`); // Fail CI if critical or high vulnerabilities if ( vulnerabilities.critical > CRITICAL_THRESHOLD || vulnerabilities.high > HIGH_THRESHOLD ) { console.error( "Security audit failed: Critical or high vulnerabilities found!", ); process.exit(1); } console.log("Security audit passed!"); } catch (error) { console.error("Security audit failed:", error); process.exit(1); } } runSecurityAudit(); ``` **Why good:** Automated CI security checks block PRs with vulnerabilities, named constants for thresholds enable easy policy changes, detailed logging provides visibility into security posture, early detection prevents vulnerable code from reaching production ### Bad Example - No CI Security Checks ```typescript // BAD: No CI security checks // No automated vulnerability scanning in CI // PRs merge without security validation // Magic numbers instead of named constants if (vulns.critical > 0) { // What's the threshold policy? process.exit(1); } ``` **Why bad:** No CI security checks allow vulnerable code to merge undetected, magic numbers obscure security policy decisions, manual security reviews are inconsistent and often skipped, vulnerabilities discovered after deployment are costly to fix -
xss-prevention.md 4.5 KB
# Security Patterns - XSS Prevention Examples > XSS prevention patterns including framework auto-escaping, DOMPurify sanitization, and CSP headers. See [SKILL.md](../SKILL.md) for core concepts and [reference.md](../reference.md) for decision frameworks. **Related Examples:** - [core.md](core.md) - Essential patterns (secrets, CSRF, cookies) - [dependency-security.md](dependency-security.md) - Dependabot, CI security checks - [access-control.md](access-control.md) - CODEOWNERS, rate limiting, branch protection --- ## Pattern 1: Framework Auto-escaping and DOMPurify ### Good Example - Framework Auto-escaping ```typescript // Most frameworks auto-escape text content by default. // This is safe - user input is rendered as text, not HTML. function UserComment({ comment }: { comment: string }) { return <div>{comment}</div>; // Auto-escaped by framework } ``` ### Good Example - Sanitize with DOMPurify ```typescript import DOMPurify from "dompurify"; // IMPORTANT: DOMPurify's default allows <style> (CSS exfiltration) and <form> (CSRF). // Always use explicit whitelist for security-critical applications. const ALLOWED_TAGS = ["b", "i", "em", "strong", "a", "p", "br"]; const ALLOWED_ATTR = ["href", "title"]; function sanitizeHTML(untrusted: string): string { return DOMPurify.sanitize(untrusted, { ALLOWED_TAGS, ALLOWED_ATTR, ALLOW_DATA_ATTR: false, }); } // Usage: sanitize BEFORE injecting raw HTML into the DOM const safeHTML = sanitizeHTML(userContent); element.innerHTML = safeHTML; ``` **Why good:** Framework auto-escaping prevents XSS by converting user input to safe text, DOMPurify whitelist approach only allows explicitly permitted tags, named constants make security policy clear and auditable ### Bad Example - Unsanitized HTML Injection ```typescript // BAD: Injecting raw user content as HTML element.innerHTML = userContent; // Arbitrary script execution! // BAD: Magic array values hide security policy const clean = DOMPurify.sanitize(html, { ALLOWED_TAGS: ["b", "i"], // What's the policy? Why these tags? }); ``` **Why bad:** Raw HTML injection without sanitization allows arbitrary script execution via user input, XSS attacks can steal cookies/tokens or perform actions as the user, magic array values hide security policy decisions --- ## Pattern 2: Content Security Policy ### Good Example - Content Security Policy ```typescript // Security headers - apply via your framework's middleware or server config const securityHeaders: Record<string, string> = { "Content-Security-Policy": [ "default-src 'self'", // Strict CSP with nonce + strict-dynamic for CSP Level 3 // 'strict-dynamic' allows trusted scripts to load additional scripts // 'unsafe-inline' is ignored by browsers when nonce is present (fallback for old browsers) "script-src 'nonce-{NONCE}' 'strict-dynamic' https: 'unsafe-inline'", "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https:", "font-src 'self' data:", "connect-src 'self' https://api.example.com", "object-src 'none'", // Prevent plugin execution (Flash, Java) "frame-ancestors 'none'", "base-uri 'none'", // Prevent base tag hijacking "form-action 'self'", ].join("; "), // Prevent MIME-type sniffing "X-Content-Type-Options": "nosniff", // Prevent clickjacking "X-Frame-Options": "DENY", // X-XSS-Protection is deprecated - set to "0" to prevent legacy browser issues. // Rely on CSP for XSS protection instead. "X-XSS-Protection": "0", }; // Apply headers in your server/middleware for (const [key, value] of Object.entries(securityHeaders)) { response.headers.set(key, value); } ``` **Why good:** CSP prevents unauthorized script execution even if XSS occurs, nonce + strict-dynamic is the modern best practice (CSP Level 3), object-src 'none' blocks plugin exploits, base-uri 'none' prevents base tag hijacking, X-Frame-Options prevents clickjacking, X-XSS-Protection set to 0 disables deprecated browser filter that can cause vulnerabilities ### Bad Example - No CSP Configuration ```typescript // BAD: No CSP configuration // No Content-Security-Policy headers // Allows inline scripts from anywhere // No XSS protection headers // BAD: Overly permissive CSP const badCSP = "default-src *; script-src * 'unsafe-inline' 'unsafe-eval'"; ``` **Why bad:** Missing CSP headers allow any script to execute enabling XSS exploitation, overly permissive CSP defeats the purpose of having a policy, 'unsafe-inline' and 'unsafe-eval' allow common XSS attack vectors, no X-Frame-Options enables clickjacking attacks
-
-
reference.md 5 KB
# Security Patterns - Reference Guide This file contains decision frameworks, red flags, and anti-patterns for security. Referenced from [SKILL.md](SKILL.md). **Examples:** - [examples/core.md](examples/core.md) - Essential patterns (secrets, CSRF, cookies) - [examples/xss-prevention.md](examples/xss-prevention.md) - XSS protection, DOMPurify, CSP headers - [examples/dependency-security.md](examples/dependency-security.md) - Dependabot, CI security checks - [examples/access-control.md](examples/access-control.md) - CODEOWNERS, rate limiting, branch protection --- <decision_framework> ## Decision Framework ``` Is it a secret (API key, password, token)? ├─ YES → Environment variable (.env.local for dev, CI secrets for production) │ └─ Rotate quarterly or on team member departure └─ NO → Is it user input being rendered? ├─ YES → Does it need to be HTML? │ ├─ YES → Sanitize with DOMPurify first │ └─ NO → Use framework auto-escaping (default) └─ NO → Is it an authentication token? ├─ YES → HttpOnly cookie (server-side) │ └─ Short-lived access token in memory (client-side) └─ NO → Is it a dependency with vulnerabilities? ├─ YES → Severity? │ ├─ Critical → Patch within 24 hours │ ├─ High → Patch within 1 week │ ├─ Medium → Patch within 1 month │ └─ Low → Next regular update └─ NO → Is it a state-changing operation (POST/PUT/DELETE)? ├─ YES → Use CSRF token + SameSite cookies └─ NO → Configure CODEOWNERS for sensitive files ``` </decision_framework> --- ## Common Mistakes > See [SKILL.md](SKILL.md) `<red_flags>` for the full red flags list. Below are additional common mistakes and gotchas. - Using `.env` instead of `.env.local` (committed to repository by default) - Forgetting `HttpOnly` flag on authentication cookies (XSS can steal tokens) - Not rotating secrets after team member departure (orphaned access) - Auto-merging major dependency updates without testing (breaking changes) - Using hardcoded CSRF tokens (defeats the purpose) - Overly permissive CSP policies (allows too many script sources) - Trusting client-side validation only (easily bypassed) - Exposing internal error details to users (information leakage) - No rate limiting on API endpoints (abuse and brute force) **Additional Gotchas:** - DOMPurify sanitization happens client-side - also sanitize on server for defense in depth - CSRF tokens need refresh on expiration - handle gracefully without breaking UX - SameSite=Lax is the modern browser default and recommended for session cookies (balances security/UX) - Dependabot PRs can be noisy - group non-security updates to reduce noise - HttpOnly cookies not accessible in JavaScript - plan token refresh strategy accordingly - Branch protection "enforce_admins" can lock out admins during emergencies - plan hotfix process - NIST SP 800-63-4 (2025) recommends against periodic password rotation for users - rotate on compromise only --- <anti_patterns> ## Anti-Patterns to Avoid ### Committing Secrets to Repository ```typescript // ANTI-PATTERN: Hardcoded secrets const API_KEY = "sk_live_1234567890abcdef"; const DATABASE_URL = "postgresql://admin:password@prod.example.com:5432/db"; ``` **Why it's wrong:** Secrets in git history are exposed forever even after deletion, anyone with repo access can extract credentials. **What to do instead:** Use .env.local (gitignored) for development, CI/CD secrets for production. --- ### Storing Tokens in localStorage ```typescript // ANTI-PATTERN: localStorage for auth tokens function storeAuthToken(token: string) { localStorage.setItem("authToken", token); } ``` **Why it's wrong:** localStorage is accessible to any JavaScript including XSS attacks, tokens persist indefinitely enabling session hijacking. **What to do instead:** Use HttpOnly cookies for authentication tokens (server-set). --- ### Unsanitized HTML Rendering ```typescript // ANTI-PATTERN: Injecting raw HTML without sanitization element.innerHTML = userComment; // Arbitrary script execution! // Also applies to framework-specific APIs: // React: dangerouslySetInnerHTML={{ __html: userComment }} // Vue: v-html="userComment" // Svelte: {@html userComment} ``` **Why it's wrong:** Allows arbitrary script execution via user input, XSS attacks can steal cookies/tokens or perform actions as user. **What to do instead:** Use DOMPurify to sanitize before rendering, or rely on framework auto-escaping (the default in modern frameworks). --- ### Individual CODEOWNERS Instead of Teams ``` # ANTI-PATTERN: Individual owners .env.example @john-developer packages/auth/* @jane-engineer ``` **Why it's wrong:** Single points of failure during vacations/departures, no backup reviewers available. **What to do instead:** Use team-based ownership: `@security-team @backend-team`. </anti_patterns> -
SKILL.md 11.1 KB
--- name: shared-security-auth-security description: Secrets management, XSS prevention, CSRF protection, dependency scanning, DOMPurify sanitization, CSP headers, CODEOWNERS, HttpOnly cookies --- # Security Patterns > **Quick Guide:** Managing secrets? Use .env.local (gitignored), CI secrets, rotate on compromise or team changes. Dependency security? Enable automated scanning (Dependabot), patch critical vulns within 24hrs. XSS prevention? Modern frameworks auto-escape output by default - never bypass with raw HTML injection unless sanitized with DOMPurify. Set CSP headers. CODEOWNERS? Require security team review for auth/, .env.example, workflows. **Detailed Resources:** - For code examples, see [examples/core.md](examples/core.md) (essential patterns) - For decision frameworks and anti-patterns, see [reference.md](reference.md) **Additional Examples:** - [examples/xss-prevention.md](examples/xss-prevention.md) - XSS protection, DOMPurify, CSP headers - [examples/dependency-security.md](examples/dependency-security.md) - Dependabot, CI security checks - [examples/access-control.md](examples/access-control.md) - CODEOWNERS, rate limiting, branch protection --- <critical_requirements> ## CRITICAL: Before Using This Skill > **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants) **(You MUST NEVER commit secrets to the repository - use .env.local and CI secrets only)** **(You MUST sanitize ALL user input before rendering raw HTML - use DOMPurify before any HTML injection)** **(You MUST patch critical/high vulnerabilities within 24 hours - use Dependabot for automated scanning)** **(You MUST use HttpOnly cookies for authentication tokens - NEVER localStorage or sessionStorage)** **(You MUST configure CODEOWNERS for security-sensitive files - require security team approval)** </critical_requirements> --- **Auto-detection:** security, secrets management, XSS prevention, CSRF protection, Dependabot, vulnerability scanning, authentication, DOMPurify, CSP headers, CODEOWNERS, HttpOnly cookies **When to use:** - Managing secrets securely (never commit, use .env.local and CI secrets) - Setting up Dependabot for automated vulnerability scanning - Preventing XSS attacks (framework auto-escaping, DOMPurify, CSP headers) - Configuring CODEOWNERS for security-sensitive code - Implementing secure authentication and token storage **When NOT to use:** - For general code quality reviews (not a security concern) - For performance optimization (different domain) - For CI/CD pipeline setup (security patterns here are for code, not infrastructure) - When security review would delay critical hotfixes (document for follow-up) **Key patterns covered:** - Never commit secrets (.gitignore, CI secrets, rotation policies quarterly) - Automated dependency scanning with Dependabot (critical within 24h) - XSS prevention (framework auto-escaping, DOMPurify for HTML, CSP headers) - CSRF protection with tokens and SameSite cookies - CODEOWNERS for security-sensitive areas (.env.example, auth code, workflows) - Secure token storage (HttpOnly cookies, in-memory access tokens) --- <philosophy> ## Philosophy Security is not a feature - it's a foundation. Every line of code must be written with security in mind. Defense in depth means multiple layers of protection, so if one fails, others catch the attack. **When to use security patterns:** - Always - security is not optional - When handling user input (sanitize and validate) - When managing secrets (environment variables, rotation) - When storing authentication tokens (HttpOnly cookies) - When setting up CI/CD (vulnerability scanning, CODEOWNERS) **When NOT to compromise:** - Never skip HTTPS in production - Never trust client-side validation alone - Never commit secrets to repository - Never use localStorage for sensitive tokens - Never bypass security reviews for critical code **Core principles:** - **Least privilege**: Grant minimum necessary access - **Defense in depth**: Multiple layers of security - **Fail securely**: Default to deny, not allow - **Don't trust user input**: Always validate and sanitize - **Assume breach**: Plan for when (not if) attacks happen </philosophy> --- <patterns> ## Core Patterns ### Pattern 1: Secret Management Never commit secrets to the repository. Use environment variables in .env.local (gitignored) for development, and CI/CD secret managers for production. Rotate secrets quarterly or on team member departure. #### What Are Secrets Secrets include: API keys, tokens, passwords, database credentials, private keys, certificates, OAuth client secrets, encryption keys, JWT secrets. #### Where to Store Secrets **Development:** - `.env.local` (gitignored) - Per-developer local overrides - Never committed to repository **CI/CD:** - GitHub Secrets - Vercel Environment Variables - GitLab CI/CD Variables - Other platform secret managers **Production:** - Environment variables (injected by platform) - Secret management services (AWS Secrets Manager, HashiCorp Vault) - Never hardcoded in code #### Rotation Policies **Note:** NIST SP 800-63-4 (2025) recommends against mandatory periodic password rotation for users. Instead, use event-based rotation (on compromise, team member departure, or security incident). Periodic rotation is still recommended for service accounts and privileged access. | Secret Type | Rotation Frequency | | ---------------------------- | --------------------------------------- | | Service account credentials | 90 days (quarterly) | | API keys | 365 days (annually) or on compromise | | User passwords | On compromise only (NIST 2025 guidance) | | Privileged account passwords | 90 days (quarterly) | | Certificates | 30 days warning before expiry | | All secrets | Immediately on team member departure | **See [examples/core.md](examples/core.md#pattern-1-secret-management) for code examples.** --- ### Pattern 2: Dependency Security Enable automated vulnerability scanning with Dependabot to catch security issues in dependencies. Patch critical vulnerabilities within 24 hours, high within 1 week, medium within 1 month. #### Update Policies **Security updates:** - **Critical vulnerabilities** - Immediate (within 24 hours) - **High vulnerabilities** - Within 1 week - **Medium vulnerabilities** - Within 1 month - **Low vulnerabilities** - Next regular update cycle **Regular updates:** - **Patch updates** (1.2.3 -> 1.2.4) - Auto-merge if tests pass - **Minor updates** (1.2.0 -> 1.3.0) - Review changes, test, merge - **Major updates** (1.0.0 -> 2.0.0) - Plan migration, test thoroughly **See [examples/dependency-security.md](examples/dependency-security.md) for Dependabot configuration and CI security check scripts.** --- ### Pattern 3: XSS Prevention Modern UI frameworks auto-escape user input by default. Never bypass this protection with raw HTML injection unless sanitized with DOMPurify. Configure Content Security Policy (CSP) headers to block unauthorized scripts. #### Framework Auto-escaping Most frameworks escape text content automatically. Only explicit HTML injection APIs (e.g., `dangerouslySetInnerHTML`, `v-html`, `{@html}`) bypass this protection. #### DOMPurify Sanitization When HTML rendering is required, use DOMPurify with a whitelist of allowed tags and attributes. #### Content Security Policy Configure CSP headers to prevent unauthorized script execution even if XSS occurs. **See [examples/xss-prevention.md](examples/xss-prevention.md) for DOMPurify and CSP code examples.** --- ### OWASP Top 10:2025 Coverage This skill addresses the following [OWASP Top 10:2025](https://owasp.org/Top10/2025/) categories: | OWASP Category | Coverage | | ------------------------------------------ | ------------------------------------------------- | | A01: Broken Access Control | CODEOWNERS, branch protection, rate limiting | | A02: Security Misconfiguration | CSP headers, security headers, Dependabot | | A03: Software Supply Chain Failures | Dependabot, CI security audits, dependency review | | A04: Cryptographic Failures | HttpOnly/Secure cookies, HTTPS enforcement | | A05: Injection | DOMPurify, framework auto-escaping, CSP | | A07: Authentication Failures | HttpOnly cookies, session management | | A10: Mishandling of Exceptional Conditions | Fail securely principle, error handling | </patterns> --- **Defense in depth layers:** - **Secrets**: .env.local (dev) -> CI secrets -> Environment variables (production) - **XSS**: Framework auto-escaping -> DOMPurify sanitization -> CSP headers - **CSRF**: Tokens -> SameSite cookies -> Server-side validation - **Dependencies**: Automated scanning -> CI security audit -> Manual review --- <red_flags> ## RED FLAGS **High Priority Issues:** - Committing secrets to repository (.env files, API keys in code) - Injecting raw HTML with unsanitized user input (enables XSS attacks) - Storing authentication tokens in localStorage/sessionStorage (accessible to XSS) - No CSRF protection on state-changing operations (allows forged requests) - Critical/high vulnerabilities unpatched (exploit window open) **Medium Priority Issues:** - No Dependabot configuration (manual vulnerability detection only) - Missing CODEOWNERS for security-sensitive files (no automatic review) - No CSP headers configured (no script execution controls) - Individual CODEOWNERS instead of teams (single point of failure) - Trusting client-side validation only (easily bypassed) - Exposing internal error details to users (information leakage) **Gotchas & Edge Cases:** - `.env.local` is gitignored by default in some frameworks but not all - verify your `.gitignore` - DOMPurify's default config allows `<style>` and `<form>` tags - use explicit whitelist - SameSite=Strict blocks legitimate cross-site requests - use Lax for general session cookies - CSP nonces must be unique per request - generate fresh nonces server-side - X-XSS-Protection header is deprecated - set to "0" or omit, use CSP instead See [reference.md](reference.md) for common mistakes, anti-patterns with code examples, and decision frameworks. </red_flags> --- <critical_reminders> ## CRITICAL REMINDERS > **All code must follow project conventions in CLAUDE.md** **(You MUST NEVER commit secrets to the repository - use .env.local and CI secrets only)** **(You MUST sanitize ALL user input before rendering raw HTML - use DOMPurify before any HTML injection)** **(You MUST patch critical/high vulnerabilities within 24 hours - use Dependabot for automated scanning)** **(You MUST use HttpOnly cookies for authentication tokens - NEVER localStorage or sessionStorage)** **(You MUST configure CODEOWNERS for security-sensitive files - require security team approval)** **Failure to follow these rules will create security vulnerabilities enabling XSS attacks, token theft, CSRF attacks, and data breaches.** </critical_reminders>
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.