security

Comprehensive security practices based on OWASP Top 10 and industry standards.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "security" with this command: npx skills add dsantiagomj/dsmj-ai-toolkit/dsantiagomj-dsmj-ai-toolkit-security

Security Skill

Comprehensive security practices based on OWASP Top 10 and industry standards.

When to Use This Skill

Auto-invoke when:

  • Implementing authentication/authorization

  • Handling user input or form data

  • Storing or processing sensitive data

  • Building API endpoints

  • Working with databases

  • Implementing file uploads

  • Code reviews for security issues

  • Configuring CORS or CSP

Critical Security Patterns

Pattern 1: Authentication & Authorization

When: Protecting routes and resources

Good:

// ✅ Proper auth check export async function GET(req: Request) { const session = await getSession(req)

if (!session) { return new Response('Unauthorized', { status: 401 }) }

const data = await db.user.findUnique({ where: { id: session.userId } }) return Response.json(data) }

// ✅ Role-based access export async function DELETE(req: Request, { params }) { const session = await getSession(req)

if (!session) { return new Response('Unauthorized', { status: 401 }) }

if (session.role !== 'admin') { return new Response('Forbidden', { status: 403 }) }

await db.user.delete({ where: { id: params.id } }) return new Response(null, { status: 204 }) }

Bad:

// ❌ No auth check export async function GET(req: Request) { const userId = req.headers.get('user-id') const data = await db.user.findUnique({ where: { id: userId } }) return Response.json(data) // Returns ANY user's data! }

Why: Always verify authentication before accessing protected resources. Check authorization (role/ownership) before operations.

Pattern 2: Password Security

When: Storing and verifying passwords

Good:

// ✅ Hash passwords with bcrypt import bcrypt from 'bcryptjs'

const hashedPassword = await bcrypt.hash(password, 12) await db.user.create({ data: { email, password: hashedPassword, } })

// Verify password const isValid = await bcrypt.compare(inputPassword, user.password)

Bad:

// ❌ NEVER store plain text passwords await db.user.create({ data: { email, password: password, // NEVER DO THIS } })

Why: Passwords must be hashed with bcrypt/argon2 (minimum 12 rounds). Never store plain text.

Pattern 3: SQL Injection Prevention

When: Executing database queries

Good:

// ✅ Use parameterized queries const userId = req.query.id await db.user.findUnique({ where: { id: userId } // ORM handles escaping })

// ✅ Or with raw SQL, use parameters await db.$queryRawSELECT * FROM users WHERE id = ${userId}

Bad:

// ❌ VULNERABLE: String concatenation const userId = req.query.id const query = SELECT * FROM users WHERE id = ${userId} await db.execute(query) // SQL Injection risk!

Why: Never concatenate user input into SQL. Use ORMs or parameterized queries.

Pattern 4: Input Validation

When: Handling user input

Good:

// ✅ Validate all input import { z } from 'zod'

const userSchema = z.object({ email: z.string().email(), password: z.string().min(12), age: z.number().int().min(18) })

export async function POST(request: Request) { const body = await request.json()

const result = userSchema.safeParse(body) if (!result.success) { return NextResponse.json( { error: result.error.format() }, { status: 400 } ) }

const user = await db.user.create({ data: result.data }) return NextResponse.json(user, { status: 201 }) }

Bad:

// ❌ No validation export async function POST(request: Request) { const body = await request.json() const user = await db.user.create({ data: body }) return NextResponse.json(user) }

Why: Always validate and sanitize user input. Never trust client data.

Pattern 5: CORS Configuration

When: Setting up API access

Good:

// ✅ Restrictive CORS app.use(cors({ origin: ['https://yourapp.com', 'https://admin.yourapp.com'], credentials: true, methods: ['GET', 'POST', 'PUT', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'] }))

Bad:

// ❌ Allow all origins with credentials app.use(cors({ origin: '*', credentials: true }))

Why: Restrictive CORS prevents unauthorized cross-origin requests.

Pattern 6: Error Handling

When: Returning error messages

Good:

// ✅ Generic errors in production app.get('/api/user/:id', async (req, res) => { try { const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]) res.json(user) } catch (error) { console.error('Database error:', error) // Log server-side res.status(500).json({ error: 'Internal server error' }) } })

Bad:

// ❌ Exposes implementation details app.get('/api/user/:id', async (req, res) => { try { const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]) res.json(user) } catch (error) { res.status(500).json({ error: error.message, stack: error.stack }) } })

Why: Never expose stack traces or internal details in production.

Code Examples

Example 1: Secure Authentication Endpoint

import bcrypt from 'bcryptjs'; import { z } from 'zod';

const loginSchema = z.object({ email: z.string().email(), password: z.string().min(12), });

export async function POST(request: Request) { const body = await request.json();

const result = loginSchema.safeParse(body); if (!result.success) { return new Response('Invalid input', { status: 400 }); }

const user = await db.user.findUnique({ where: { email: result.data.email } });

if (!user || !(await bcrypt.compare(result.data.password, user.password))) { return new Response('Invalid credentials', { status: 401 }); }

const session = await createSession(user.id); return NextResponse.json({ session }); }

Example 2: Input Validation with Zod

const userSchema = z.object({ name: z.string().min(2).max(100), email: z.string().email(), age: z.number().int().min(18).max(120), role: z.enum(['USER', 'ADMIN']), });

export async function POST(request: Request) { const body = await request.json(); const result = userSchema.safeParse(body);

if (!result.success) { return NextResponse.json( { error: result.error.format() }, { status: 400 } ); }

const user = await db.user.create({ data: result.data }); return NextResponse.json(user, { status: 201 }); }

For comprehensive examples and detailed implementations, see the references/ folder.

Quick Security Checklist

Before deploying:

  • All secrets in environment variables (not code)

  • Passwords hashed with bcrypt/argon2 (rounds ≥ 12)

  • Input validation on all user inputs

  • Parameterized queries (no string concatenation in SQL)

  • HTTPS enforced

  • CORS configured restrictively

  • Security headers configured (CSP, HSTS, etc.)

  • Rate limiting on auth endpoints

  • Logging for security events

  • Dependencies updated (npm audit clean)

  • Authentication on all protected routes

  • Authorization checks before operations

  • Error messages don't leak information

Progressive Disclosure

For detailed information, see:

  • OWASP Top 10 Details - Complete OWASP Top 10 analysis with examples

  • Authentication Patterns - JWT, sessions, MFA, input validation

References

  • OWASP Top 10 Details

  • Authentication Patterns

This skill covers security fundamentals. Always stay updated with latest OWASP guidelines and security best practices.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

caching

No summary provided by upstream source.

Repository SourceNeeds Review
General

vercel-ai-sdk

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

typescript

No summary provided by upstream source.

Repository SourceNeeds Review