.fyi
SkillsMCPPluginsSubagents

Browse by category

DevOps & CI/CD SkillsProductivity & Workflow SkillsOther SkillsProduct & Project Management SkillsDocumentation & Knowledge SkillsCode Review & Refactor SkillsBackend & APIs SkillsAgent Meta & Communication SkillsResearch SkillsSecurity SkillsUX UI & Design SkillsTesting & QA SkillsSee all →

Every Claude Code skill, MCP server, plugin and subagent in one directory. Searchable, comparable, and one command from installed. Live stats from GitHub, npm and PyPI.

We're on Product HuntYour agent's app storeCheck it out →
Agent SkillsMCP ServersPluginsSubagentsCoding Agents
CollectionsOfficial publishersGlossaryFAQBlogSearchSavedFeedback
PrivacyTermsllms.txtSitemap

made with ♥ · © 2026 aaaa.fyi

Independent project · real data from public registries

…/agent-skills/security-and-hardening
home/skills/addyosmani/agent-skills/security-and-hardening
addyosmani avatar

security-and-hardening

byaddyosmani· 31 skills

Installs

16k

Stars

80k

Forks

8.7k

Category

Security

View on GitHub

TL;DR

Hardens code against vulnerabilities. Use when handling user input, authentication, data storage, or external integrations. Use when building any feature that accepts untrusted data, manages user sessions, or interacts with third-party services.

How to install security-and-hardening?

addyosmani/agent-skills/security-and-hardening
$npx -y skills add addyosmani/agent-skills --skill security-and-hardening

Installs into the current project.

›Prefer a prompt? Paste this to your agent

Use this skill

Run `npx skills use "https://github.com/addyosmani/agent-skills" --skill "addyosmani/agent-skills/security-and-hardening"` and follow the generated skill instructions now. Read its complete output, redirecting it to a temporary file first if necessary. Resolve relative paths from the supporting-files directory it provides.

Use the whole pack

Use the skills in "https://github.com/addyosmani/agent-skills" that are relevant to the current task. Run `npx skills add "https://github.com/addyosmani/agent-skills"` and select the relevant skills, then follow their instructions.

Files · 1

View on GitHub
SKILL.md
1# Security and Hardening
2 
3## Overview
4 
5Security-first development practices for web applications. Treat every external input as hostile, every secret as sacred, and every authorization check as mandatory. Security isn't a phase — it's a constraint on every line of code that touches user data, authentication, or external systems.
6 
7## When to Use
8 
9- Building anything that accepts user input
10- Implementing authentication or authorization
11- Storing or transmitting sensitive data
12- Integrating with external APIs or services
13- Adding file uploads, webhooks, or callbacks
14- Handling payment or PII data
15 
16## Process: Threat Model First
17 
18Controls bolted on without a threat model are guesses. Before hardening, spend five minutes thinking like an attacker:
19 
201. **Map the trust boundaries.** Where does untrusted data cross into your system? HTTP requests, form fields, file uploads, webhooks, third-party APIs, message queues, and **LLM output**. Every boundary is attack surface.
212. **Name the assets.** What's worth stealing or breaking? Credentials, PII, payment data, admin actions, money movement.
223. **Run STRIDE over each boundary** — a quick lens, not a ceremony:
23 
24| Threat | Ask | Typical mitigation |
25|---|---|---|
26| **S**poofing | Can someone impersonate a user/service? | Authentication, signature verification |
27| **T**ampering | Can data be altered in transit or at rest? | Integrity checks, parameterized queries, HTTPS |
28| **R**epudiation | Can an action be denied later? | Audit logging of security events |
29| **I**nformation disclosure | Can data leak? | Encryption, field allowlists, generic errors |
30| **D**enial of service | Can it be overwhelmed? | Rate limiting, input size caps, timeouts |
31| **E**levation of privilege | Can a user gain rights they shouldn't? | Authorization checks, least privilege |
32 
334. **Write abuse cases next to use cases.** For each feature, ask "how would I misuse this?" — then make that your first test.
34 
35If you can't name the trust boundaries for a feature, you're not ready to secure it. This is OWASP **A04: Insecure Design** — most breaches begin in design, not code.
36 
37## The Three-Tier Boundary System
38 
39### Always Do (No Exceptions)
40 
41- **Validate all external input** at the system boundary (API routes, form handlers)
42- **Parameterize all database queries** — never concatenate user input into SQL
43- **Encode output** to prevent XSS (use framework auto-escaping, don't bypass it)
44- **Use HTTPS** for all external communication
45- **Hash passwords** with bcrypt/scrypt/argon2 (never store plaintext)
46- **Set security headers** (CSP, HSTS, X-Frame-Options, X-Content-Type-Options)
47- **Use httpOnly, secure, sameSite cookies** for sessions
48- **Run the detected package manager's native audit** against the committed lockfile before every release
49 
50### Ask First (Requires Human Approval)
51 
52- Adding new authentication flows or changing auth logic
53- Storing new categories of sensitive data (PII, payment info)
54- Adding new external service integrations
55- Changing CORS configuration
56- Adding file upload handlers
57- Modifying rate limiting or throttling
58- Granting elevated permissions or roles
59 
60### Never Do
61 
62- **Never commit secrets** to version control (API keys, passwords, tokens)
63- **Never log sensitive data** (passwords, tokens, full credit card numbers)
64- **Never trust client-side validation** as a security boundary
65- **Never disable security headers** for convenience
66- **Never use `eval()` or `innerHTML`** with user-provided data
67- **Never store sessions in client-accessible storage** (localStorage for auth tokens)
68- **Never expose stack traces** or internal error details to users
69 
70## OWASP Top 10 Prevention Patterns
71 
72These are prevention patterns, not a ranking. For the 2021 ordering, see the quick-reference table in `references/security-checklist.md`.
73 
74### Injection (SQL, NoSQL, OS Command)
75 
76```typescript
77// BAD: SQL injection via string concatenation
78const query = `SELECT * FROM users WHERE id = '${userId}'`;
79 
80// GOOD: Parameterized query
81const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
82 
83// GOOD: ORM with parameterized input
84const user = await prisma.user.findUnique({ where: { id: userId } });
85```
86 
87### Broken Authentication
88 
89```typescript
90// Password hashing
91import { hash, compare } from 'bcrypt';
92 
93const SALT_ROUNDS = 12;
94const hashedPassword = await hash(plaintext, SALT_ROUNDS);
95const isValid = await compare(plaintext, hashedPassword);
96 
97// Session management
98app.use(session({
99 secret: process.env.SESSION_SECRET, // From environment, not code
100 resave: false,
101 saveUninitialized: false,
102 cookie: {
103 httpOnly: true, // Not accessible via JavaScript
104 secure: true, // HTTPS only
105 sameSite: 'lax', // CSRF protection
106 maxAge: 24 * 60 * 60 * 1000, // 24 hours
107 },
108}));
109```
110 
111### Cross-Site Scripting (XSS)
112 
113```typescript
114// BAD: Rendering user input as HTML
115element.innerHTML = userInput;
116 
117// GOOD: Use framework auto-escaping (React does this by default)
118return <div>{userInput}</div>;
119 
120// If you MUST render HTML, sanitize first
121import DOMPurify from 'dompurify';
122const clean = DOMPurify.sanitize(userInput);
123```
124 
125### Broken Access Control
126 
127```typescript
128// Always check authorization, not just authentication
129app.patch('/api/tasks/:id', authenticate, async (req, res) => {
130 const task = await taskService.findById(req.params.id);
131 
132 // Check that the authenticated user owns this resource
133 if (task.ownerId !== req.user.id) {
134 return res.status(403).json({
135 error: { code: 'FORBIDDEN', message: 'Not authorized to modify this task' }
136 });
137 }
138 
139 // Proceed with update
140 const updated = await taskService.update(req.params.id, req.body);
141 return res.json(updated);
142});
143```
144 
145### Security Misconfiguration
146 
147```typescript
148// Security headers (use helmet for Express)
149import helmet from 'helmet';
150app.use(helmet());
151 
152// Content Security Policy
153app.use(helmet.contentSecurityPolicy({
154 directives: {
155 defaultSrc: ["'self'"],
156 scriptSrc: ["'self'"],
157 styleSrc: ["'self'", "'unsafe-inline'"], // Tighten if possible
158 imgSrc: ["'self'", 'data:', 'https:'],
159 connectSrc: ["'self'"],
160 },
161}));
162 
163// CORS — restrict to known origins
164app.use(cors({
165 origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000',
166 credentials: true,
167}));
168```
169 
170### Sensitive Data Exposure
171 
172```typescript
173// Never return sensitive fields in API responses
174function sanitizeUser(user: UserRecord): PublicUser {
175 const { passwordHash, resetToken, ...publicFields } = user;
176 return publicFields;
177}
178 
179// Use environment variables for secrets
180const API_KEY = process.env.STRIPE_API_KEY;
181if (!API_KEY) throw new Error('STRIPE_API_KEY not configured');
182```
183 
184### Server-Side Request Forgery (SSRF)
185 
186Any time the server fetches a URL the user influenced — webhooks, "import from URL", image proxies, link previews — an attacker can aim it at internal services (cloud metadata, `localhost`, private IPs).
187 
188```typescript
189// BAD: fetch whatever the user gives you
190await fetch(req.body.webhookUrl);
191 
192// GOOD: allowlist scheme + host, reject if ANY resolved IP is private, forbid redirects
193import { lookup } from 'node:dns/promises';
194import ipaddr from 'ipaddr.js';
195 
196const ALLOWED_HOSTS = new Set(['hooks.example.com']);
197 
198async function assertSafeUrl(raw: string): Promise<URL> {
199 const url = new URL(raw);
200 if (url.protocol !== 'https:') throw new Error('https only');
201 if (!ALLOWED_HOSTS.has(url.hostname)) throw new Error('host not allowed');
202 // Resolve ALL records; a single private/reserved address fails the check.
203 const addrs = await lookup(url.hostname, { all: true });
204 if (addrs.some((a) => ipaddr.parse(a.address).range() !== 'unicast')) {
205 throw new Error('private/reserved IP');
206 }
207 return url;
208}
209 
210await fetch(await assertSafeUrl(req.body.webhookUrl), { redirect: 'error' });
211```
212 
213The `range() !== 'unicast'` check covers loopback, link-local `169.254.169.254` (cloud metadata, the #1 SSRF target), private, and unique-local ranges across IPv4 and IPv6.
214 
215**Caveat — this still has a TOCTOU gap.** `fetch` resolves DNS again after the check, so an attacker using a short-TTL record can rebind to an internal IP between validation and connection. For high-risk surfaces, resolve once and connect to the pinned IP, or put a filtering agent in front (`request-filtering-agent` / `ssrf-req-filter`).
216 
217## Input Validation Patterns
218 
219### Schema Validation at Boundaries
220 
221```typescript
222import { z } from 'zod';
223 
224const CreateTaskSchema = z.object({
225 title: z.string().min(1).max(200).trim(),
226 description: z.string().max(2000).optional(),
227 priority: z.enum(['low', 'medium', 'high']).default('medium'),
228 dueDate: z.string().datetime().optional(),
229});
230 
231// Validate at the route handler
232app.post('/api/tasks', async (req, res) => {
233 const result = CreateTaskSchema.safeParse(req.body);
234 if (!result.success) {
235 return res.status(422).json({
236 error: {
237 code: 'VALIDATION_ERROR',
238 message: 'Invalid input',
239 details: result.error.flatten(),
240 },
241 });
242 }
243 // result.data is now typed and validated
244 const task = await taskService.create(result.data);
245 return res.status(201).json(task);
246});
247```
248 
249### File Upload Safety
250 
251```typescript
252// Restrict file types and sizes
253const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
254const MAX_SIZE = 5 * 1024 * 1024; // 5MB
255 
256function validateUpload(file: UploadedFile) {
257 if (!ALLOWED_TYPES.includes(file.mimetype)) {
258 throw new ValidationError('File type not allowed');
259 }
260 if (file.size > MAX_SIZE) {
261 throw new ValidationError('File too large (max 5MB)');
262 }
263 // Don't trust the file extension — check magic bytes if critical
264}
265```
266 
267## Triaging Dependency Audit Results
268 
269Package-manager audits report known advisories; they do not prove a package is trustworthy or that vulnerable code is reachable. Use this decision tree:
270 
271```
272The native package-manager audit reports a vulnerability
273├── Severity: critical or high
274│ ├── Is the vulnerable code reachable in runtime, build, test, or deployment paths?
275│ │ ├── YES --> Fix immediately (update, patch, or replace the dependency)
276│ │ └── NO (confirmed unused across those paths) --> Fix soon, but not a blocker
277│ └── Is a fix available?
278│ ├── YES --> Update to the patched version
279│ └── NO --> Check for workarounds, consider replacing the dependency, or add to allowlist with a review date
280├── Severity: moderate
281│ ├── Reachable in production? --> Fix in the next release cycle
282│ └── Dev-only? --> Fix when convenient, track in backlog
283└── Severity: low
284 └── Track and fix during regular dependency updates
285```
286 
287**Key questions:**
288- Is the vulnerable function actually called in your code path?
289- Is the dependency a runtime dependency or dev-only?
290- Is the vulnerability exploitable given your deployment context (e.g., a server-side vulnerability in a client-only app)?
291 
292When you defer a fix, document the reason and set a review date.
293 
294### Supply-Chain Hygiene
295 
296Do not assume npm or treat the nearest manifest as the install root. Apply this order:
297 
2981. **Find the installation boundary and manager.** Use the workspace root that owns the lockfile, or an independent nested project only when it is outside that workspace. There, corroborate `packageManager` (when present), the lockfile, and CI; stop on disagreement or competing lockfiles. Pin the manager version and use the matrix in `references/security-checklist.md`.
2992. **Block dependency scripts before first execution.** Bootstrap with scripts disabled or a documented fail-closed policy, inspect the pending script source, approve only the minimum required packages, commit the policy, then verify with a clean frozen/immutable install. Never blanket-approve scripts.
300 
301Audits only find known advisories; they do not catch a newly malicious or typosquatted package. Therefore:
302 
303- **Never apply forced audit remediation automatically** (`npm audit fix --force` or equivalent). Preview the remediation, read changelogs, and test each resulting upgrade; forced fixes may cross declared dependency ranges.
304- **Verify registry signatures and provenance where supported** (`npm audit signatures`, `pnpm audit signatures`) and treat absence as a signal to investigate, not automatic proof of compromise.
305- **Review new dependencies, lockfile diffs, and script-policy changes together** — ownership, maintenance, release age, provenance, transitive graph, and typosquats such as `cross-env` vs `crossenv` (OWASP **A06**, **LLM03**).
306 
307## Rate Limiting
308 
309```typescript
310import rateLimit from 'express-rate-limit';
311 
312// General API rate limit
313app.use('/api/', rateLimit({
314 windowMs: 15 * 60 * 1000, // 15 minutes
315 max: 100, // 100 requests per window
316 standardHeaders: true,
317 legacyHeaders: false,
318}));
319 
320// Stricter limit for auth endpoints
321app.use('/api/auth/', rateLimit({
322 windowMs: 15 * 60 * 1000,
323 max: 10, // 10 attempts per 15 minutes
324}));
325```
326 
327## Secrets Management
328 
329```
330.env files:
331 ├── .env.example → Committed (template with placeholder values)
332 ├── .env → NOT committed (contains real secrets)
333 └── .env.local → NOT committed (local overrides)
334 
335.gitignore must include:
336 .env
337 .env.local
338 .env.*.local
339 *.pem
340 *.key
341```
342 
343**Always check before committing:**
344```bash
345# Check for accidentally staged secrets
346git diff --cached | grep -i "password\|secret\|api_key\|token"
347```
348 
349**If a secret is ever committed, rotate it.** Deleting the line or rewriting history is not enough — assume it's compromised the moment it reaches a remote. Revoke and reissue the key first, then purge it from history.
350 
351## Securing AI / LLM Features
352 
353If your app calls an LLM — chatbots, summarizers, agents, RAG — it inherits a new attack surface. Map it to the [OWASP Top 10 for LLM Applications (2025)](https://genai.owasp.org/llm-top-10/):
354 
355- **Treat all model output as untrusted input (LLM05: Improper Output Handling).** Never pass LLM output straight into `eval`, SQL, a shell, `innerHTML`, or a file path. Validate and encode it exactly as you would raw user input.
356- **Assume prompts can be hijacked (LLM01: Prompt Injection).** Untrusted text in the context window — a user message, a fetched web page, a PDF — can carry instructions. The system prompt is not a security boundary; enforce permissions in code, not in the prompt.
357- **Keep secrets and other users' data out of prompts (LLM02 / LLM07).** Anything in the context can be echoed back. Don't put API keys, cross-tenant data, or the full system prompt where the model can repeat it.
358- **Constrain tool and agent permissions (LLM06: Excessive Agency).** Scope tools to the minimum, require confirmation for destructive or irreversible actions, and validate every tool argument.
359- **Bound consumption (LLM10: Unbounded Consumption).** Cap tokens, request rate, and loop/recursion depth so a crafted input can't run up cost or hang the system.
360- **Isolate retrieval data (LLM08: Vector and Embedding Weaknesses).** In RAG, treat the vector store as a trust boundary: partition embeddings per tenant so one user can't retrieve another's data, and validate documents before indexing so poisoned content can't steer answers.
361 
362```typescript
363// BAD: trusting model output as a command or as markup
364const sql = await llm.generate(`Write SQL for: ${userQuestion}`);
365await db.query(sql); // arbitrary query execution
366container.innerHTML = await llm.reply(userMessage); // stored XSS, via the model
367 
368// GOOD: model output is data — parse defensively, then validate, then encode
369let intent;
370try {
371 intent = CommandSchema.parse(JSON.parse(await llm.replyJson(userMessage)));
372} catch {
373 throw new ValidationError('unexpected model output'); // JSON.parse or schema failed
374}
375await runAllowlistedAction(intent.action, intent.params);
376container.textContent = await llm.reply(userMessage);
377```
378 
379## Security Review Checklist
380 
381```markdown
382### Authentication
383- [ ] Passwords hashed with bcrypt/scrypt/argon2 (salt rounds ≥ 12)
384- [ ] Session tokens are httpOnly, secure, sameSite
385- [ ] Login has rate limiting
386- [ ] Password reset tokens expire
387 
388### Authorization
389- [ ] Every endpoint checks user permissions
390- [ ] Users can only access their own resources
391- [ ] Admin actions require admin role verification
392 
393### Input
394- [ ] All user input validated at the boundary
395- [ ] SQL queries are parameterized
396- [ ] HTML output is encoded/escaped
397- [ ] Server-side URL fetches are allowlisted (no SSRF to internal services)
398 
399### Data
400- [ ] No secrets in code or version control
401- [ ] Sensitive fields excluded from API responses
402- [ ] PII encrypted at rest (if applicable)
403 
404### Infrastructure
405- [ ] Security headers configured (CSP, HSTS, etc.)
406- [ ] CORS restricted to known origins
407- [ ] Dependencies audited for vulnerabilities
408- [ ] Error messages don't expose internals
409 
410### Supply Chain
411- [ ] One authoritative lockfile committed; CI uses that manager's frozen/immutable install
412- [ ] Native audit triaged by reachability and fix risk; dependency install scripts blocked unless explicitly approved
413- [ ] New dependencies reviewed (ownership, provenance, release age, transitive graph)
414 
415### AI / LLM (if used)
416- [ ] Model output treated as untrusted (no eval/SQL/innerHTML/shell)
417- [ ] Secrets and other users' data kept out of prompts
418- [ ] Tool/agent permissions scoped; destructive actions require confirmation
419```
420## See Also
421 
422For detailed security checklists and pre-commit verification steps, see `references/security-checklist.md`.
423 
424## Common Rationalizations
425 
426| Rationalization | Reality |
427|---|---|
428| "This is an internal tool, security doesn't matter" | Internal tools get compromised. Attackers target the weakest link. |
429| "We'll add security later" | Security retrofitting is 10x harder than building it in. Add it now. |
430| "No one would try to exploit this" | Automated scanners will find it. Security by obscurity is not security. |
431| "The framework handles security" | Frameworks provide tools, not guarantees. You still need to use them correctly. |
432| "It's just a prototype" | Prototypes become production. Security habits from day one. |
433| "Threat modeling is overkill here" | Five minutes of "how would I attack this?" prevents the design flaws no control can patch later. |
434| "It's just LLM output, it's only text" | That "text" can be a SQL statement, a script tag, or a shell command. Treat it like any untrusted input. |
435| "The audit passed, so the dependency is safe" | Audits match known advisories. They do not detect a newly malicious package or make unreviewed install scripts safe to execute. |
436 
437## Red Flags
438 
439- User input passed directly to database queries, shell commands, or HTML rendering
440- Secrets in source code or commit history
441- API endpoints without authentication or authorization checks
442- Missing CORS configuration or wildcard (`*`) origins
443- No rate limiting on authentication endpoints
444- Stack traces or internal errors exposed to users
445- Dependencies with known critical vulnerabilities, competing lockfiles at one installation boundary, non-reproducible installs, or blanket-approved scripts
446- Server fetches user-supplied URLs without an allowlist (SSRF)
447- LLM/model output passed into a query, the DOM, a shell, or `eval`
448- Secrets, PII, or the full system prompt placed inside an LLM context window
449 
450## Verification
451 
452After implementing security-relevant code:
453 
454- [ ] The native audit has no unmitigated reachable critical/high findings; CI preserves the authoritative lockfile and blocks unreviewed dependency scripts
455- [ ] No secrets in source code or git history
456- [ ] All user input validated at system boundaries
457- [ ] Authentication and authorization

Security

Review

  • Gen Agent Trust Hubpass
  • Socketpass
  • Snykpass
  • Runlayerwarn
  • ZeroLeakspass

Preview

addyosmani/agent-skillsaddyosmani/agent-skills

$ npx -y skills add addyosmani/agent-skills --skill security-and-hardening

▸ installing to .claude/skills…

✓ security-and-hardening ready

Repoaddyosmani/agent-skills
TypeSkills
CategorySecurity
ForDeveloperArchitect
UpdatedJul 2026
License—
First seenJul 26, 2026

Tags

Skill

Related

6 picks
Type
  1. microsoft avatarentra-app-registrationGuides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration.SkillsJul 2026484k1.3k
  2. microsoft avatarazure-complianceRun Azure compliance and security audits with azqr plus Key Vault expiration checks.SkillsJul 2026484k1.3k
  3. microsoft avatarentra-agent-idProvision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token…SkillsJul 2026207k1.3k
  4. firebase avatarfirebase-security-rules-auditorAudits Firebase (Firestore, Cloud Storage) security rules for vulnerabilities, privilege escalation, role bypasses, create vs update inconsistencies, resource…SkillsJul 202680k389
  5. samber avatargolang-securitySecurity best practices and vulnerability prevention for Golang.SkillsJul 202635k2.7k
  6. googleworkspace avatargws-modelarmorGoogle Model Armor: Filter user-generated content for safety.SkillsJul 202624k30k