security-auditor

gregsuptown's avatarfrom gregsuptown

Scan for OWASP Top 10 vulnerabilities and security best practices. Checks for SQL injection, XSS, authentication issues, sensitive data exposure, and other common security risks.

0stars🔀0forks📁View on GitHub🕐Updated Jan 10, 2026

When & Why to Use This Skill

The Security Auditor skill is a comprehensive automated security scanner designed to identify and remediate OWASP Top 10 vulnerabilities within a codebase. By analyzing code patterns for risks like SQL injection, Cross-Site Scripting (XSS), and broken authentication, it provides developers with actionable insights and secure coding patterns to prevent data breaches and ensure robust application security before deployment.

Use Cases

  • Pre-PR Security Auditing: Automatically scan new code changes for security flaws like hardcoded secrets or unparameterized queries before merging into the main branch.
  • Vulnerability Remediation: Identify unsafe code patterns (e.g., dangerouslySetInnerHTML) and receive immediate guidance on implementing safe alternatives like DOMPurify sanitization.
  • Access Control Verification: Audit API endpoints and tRPC procedures to ensure that ownership checks and role-based access controls are correctly enforced to prevent IDOR vulnerabilities.
  • Compliance & Best Practices: Perform a comprehensive check against OWASP standards to ensure sensitive data exposure is minimized and security headers are correctly configured.
  • DevSecOps Integration: Use as a first line of defense in the development lifecycle to catch critical security risks during the coding phase rather than after deployment.
namesecurity-auditor
descriptionScan for OWASP Top 10 vulnerabilities and security best practices. Checks for SQL injection, XSS, authentication issues, sensitive data exposure, and other common security risks.
allowed-toolsRead, Grep, Glob

Security Vulnerability Auditor

Purpose

Comprehensive security scanner focused on OWASP Top 10 vulnerabilities:

  1. Injection (SQL, NoSQL, Command)
  2. Broken Authentication
  3. Sensitive Data Exposure
  4. XML External Entities (XXE)
  5. Broken Access Control
  6. Security Misconfiguration
  7. Cross-Site Scripting (XSS)
  8. Insecure Deserialization
  9. Using Components with Known Vulnerabilities
  10. Insufficient Logging & Monitoring

Auto-Invocation Triggers

This skill activates when:

  • User asks to "check security" or "audit security"
  • Before deployment to production
  • When modifying authentication/authorization code
  • When adding new tRPC procedures
  • When working with user input or database queries
  • Before creating a pull request for sensitive features

Vulnerability Patterns

1. SQL Injection (CRITICAL 🔴)

What to Look For:

  • String concatenation in SQL queries
  • Unparameterized database queries
  • Dynamic table/column names from user input

Safe Pattern (Drizzle ORM):

// ✅ SAFE - Parameterized query
const users = await db.query.users.findMany({
  where: eq(users.email, userEmail)
});

// ✅ SAFE - Prepared statement
const result = await db.select()
  .from(users)
  .where(eq(users.id, userId));

Unsafe Pattern:

// ❌ VULNERABLE - String concatenation
const query = `SELECT * FROM users WHERE email = '${userEmail}'`;
await db.execute(query);

// ❌ VULNERABLE - Template literal
const result = await db.execute(
  `SELECT * FROM ${tableName} WHERE id = ${userId}`
);

Grep Patterns:

db.execute.*\$\{
db.query.*\+.*user
SELECT.*\$\{

2. Cross-Site Scripting (XSS) (HIGH 🟠)

What to Look For:

  • dangerouslySetInnerHTML without sanitization
  • Direct DOM manipulation with user input
  • Unescaped user data in templates

Safe Pattern:

// ✅ SAFE - React auto-escapes
<div>{user.name}</div>

// ✅ SAFE - Sanitized HTML
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{
  __html: DOMPurify.sanitize(userContent)
}} />

Unsafe Pattern:

// ❌ VULNERABLE - Unsanitized HTML
<div dangerouslySetInnerHTML={{ __html: userContent }} />

// ❌ VULNERABLE - Direct DOM manipulation
element.innerHTML = userInput;

// ❌ VULNERABLE - Unescaped in template
const html = `<div>${userInput}</div>`;

Grep Patterns:

dangerouslySetInnerHTML
\.innerHTML\s*=
eval\(
Function\(

3. Broken Authentication (CRITICAL 🔴)

What to Look For:

  • Missing authentication on sensitive routes
  • JWT secrets in code or environment files
  • Weak password requirements
  • Session fixation vulnerabilities
  • Missing rate limiting on auth endpoints

Safe Pattern:

// ✅ SAFE - Protected procedure
export const deleteUser = protectedProcedure
  .input(z.object({ id: z.string() }))
  .mutation(async ({ input, ctx }) => {
    // ctx.user is guaranteed to exist
    if (ctx.user.role !== 'admin') {
      throw new TRPCError({ code: 'FORBIDDEN' });
    }
    return userService.delete(input.id);
  });

// ✅ SAFE - Session validation via Lucia
const session = await lucia.validateSession(sessionId);
if (!session) throw new TRPCError({ code: 'UNAUTHORIZED' });

Unsafe Pattern:

// ❌ VULNERABLE - Public procedure for sensitive action
export const deleteUser = publicProcedure
  .input(z.object({ id: z.string() }))
  .mutation(({ input }) => db.delete(users).where(eq(users.id, input.id)));

// ❌ VULNERABLE - Hardcoded JWT secret
const JWT_SECRET = "my-super-secret-key";

// ❌ VULNERABLE - No rate limiting
export const login = publicProcedure
  .input(loginSchema)
  .mutation(async ({ input }) => {
    // No rate limiting, vulnerable to brute force
  });

Checks:

  • All sensitive procedures use protectedProcedure
  • JWT secrets from environment, not hardcoded
  • Rate limiting on auth endpoints
  • Password hashing with bcrypt/argon2

4. Sensitive Data Exposure (HIGH 🟠)

What to Look For:

  • Passwords or hashes in responses
  • API keys in logs or error messages
  • Sensitive data in URLs or query params
  • Unencrypted sensitive data transmission
  • Sensitive data in client-side storage

Safe Pattern:

// ✅ SAFE - Exclude sensitive fields
export async function getById(id: string) {
  const { password, ...user } = await db.query.users.findFirst({
    where: eq(users.id, id)
  });
  return user;
}

// ✅ SAFE - Selective field return
const user = await db.select({
  id: users.id,
  email: users.email,
  name: users.name
  // password intentionally omitted
}).from(users).where(eq(users.id, id));

Unsafe Pattern:

// ❌ VULNERABLE - Returns full user object (includes password hash)
export async function getById(id: string) {
  return await db.query.users.findFirst({
    where: eq(users.id, id)
  });
}

// ❌ VULNERABLE - Logging sensitive data
console.log('Login attempt:', { email, password });

// ❌ VULNERABLE - Sensitive data in error
throw new Error(`Login failed for ${email} with password ${password}`);

Checks:

  • User objects never include password fields
  • No logging of passwords, tokens, or API keys
  • HTTPS enforced in production
  • Sensitive data not in localStorage (use httpOnly cookies)

5. Broken Access Control (HIGH 🟠)

What to Look For:

  • Missing ownership checks
  • Horizontal privilege escalation (user accessing another user's data)
  • Vertical privilege escalation (user accessing admin functions)
  • Insecure direct object references (IDOR)

Safe Pattern:

// ✅ SAFE - Ownership verification
export async function updateProject(
  id: string,
  data: Partial<Project>,
  userId: string
) {
  const project = await getById(id);

  // Verify ownership
  if (project.userId !== userId) {
    throw new TRPCError({ code: 'FORBIDDEN' });
  }

  return await db.update(projects)
    .set(data)
    .where(eq(projects.id, id));
}

// ✅ SAFE - Role-based access
export const adminAction = protectedProcedure
  .use(requireRole('admin'))
  .mutation(async ({ ctx }) => {
    // Only admins reach here
  });

Unsafe Pattern:

// ❌ VULNERABLE - No ownership check
export async function updateProject(id: string, data: Partial<Project>) {
  // Any authenticated user can update any project!
  return await db.update(projects)
    .set(data)
    .where(eq(projects.id, id));
}

// ❌ VULNERABLE - IDOR
export const getProject = publicProcedure
  .input(z.object({ id: z.string() }))
  .query(({ input }) => {
    // Returns any project by ID, no access control
    return db.query.projects.findFirst({
      where: eq(projects.id, input.id)
    });
  });

Checks:

  • All data access checks ownership (userId match)
  • Admin functions check role/permissions
  • Resource IDs validated against user context
  • No direct object reference without authorization

6. Security Misconfiguration (MEDIUM 🟡)

What to Look For:

  • CORS misconfiguration (allow all origins)
  • Missing security headers
  • Default credentials
  • Verbose error messages in production
  • Unnecessary services enabled

Safe Pattern:

// ✅ SAFE - Specific CORS origins
app.use(cors({
  origin: process.env.NODE_ENV === 'production'
    ? ['https://studio535.com', 'https://app.studio535.com']
    : ['http://localhost:5000'],
  credentials: true
}));

// ✅ SAFE - Security headers
app.use(helmet({
  contentSecurityPolicy: true,
  hsts: true,
  noSniff: true
}));

// ✅ SAFE - Generic error in production
if (process.env.NODE_ENV === 'production') {
  return res.status(500).json({ error: 'Internal server error' });
} else {
  return res.status(500).json({ error: error.message, stack: error.stack });
}

Unsafe Pattern:

// ❌ VULNERABLE - Allow all origins
app.use(cors({ origin: '*' }));

// ❌ VULNERABLE - No security headers
// Missing helmet() or equivalent

// ❌ VULNERABLE - Verbose errors in production
app.use((err, req, res, next) => {
  res.status(500).json({
    error: err.message,
    stack: err.stack,
    query: req.query
  });
});

Checks:

  • CORS configured for specific origins
  • Helmet or equivalent security headers
  • Generic error messages in production
  • No default credentials in code

7. Command Injection (CRITICAL 🔴)

What to Look For:

  • User input in shell commands
  • Unvalidated file paths
  • System command execution with template literals

Safe Pattern:

// ✅ SAFE - Use library instead of shell
import { readFile } from 'fs/promises';
const content = await readFile(filePath, 'utf-8');

// ✅ SAFE - Whitelist validation
const allowedCommands = ['build', 'test', 'lint'];
if (!allowedCommands.includes(userCommand)) {
  throw new Error('Invalid command');
}
exec(userCommand); // Now safe

Unsafe Pattern:

// ❌ VULNERABLE - User input in command
exec(`convert ${userFilePath} output.png`);

// ❌ VULNERABLE - Template literal with user data
child_process.exec(`git clone ${userRepo}`);

// ❌ VULNERABLE - Unvalidated file path
fs.readFile(`./uploads/${userFileName}`, ...);

Grep Patterns:

exec\(.*\$\{
spawn\(.*\+
child_process.*user

8. Insufficient Logging (LOW 🟢)

What to Look For:

  • Authentication failures not logged
  • Authorization failures not logged
  • Critical actions not audited
  • No logging of security events

Safe Pattern:

// ✅ SAFE - Log security events
logger.warn('Failed login attempt', {
  email: input.email,
  ip: req.ip,
  timestamp: new Date()
});

logger.info('User deleted', {
  deletedBy: ctx.user.id,
  deletedUser: userId,
  timestamp: new Date()
});

Checks:

  • Failed login attempts logged
  • Authorization failures logged
  • Admin actions audited
  • Rate limit violations logged

Scan Process

Step 1: Critical Vulnerabilities

Scan for patterns that could lead to immediate compromise:

  1. SQL injection patterns
  2. Command injection patterns
  3. Hardcoded secrets
  4. Missing authentication on sensitive routes

Step 2: High-Risk Issues

Scan for patterns that could lead to data exposure:

  1. XSS vulnerabilities
  2. Sensitive data in responses
  3. Broken access control
  4. Missing ownership checks

Step 3: Medium-Risk Issues

Scan for configuration and design issues:

  1. CORS misconfiguration
  2. Missing security headers
  3. Weak error handling
  4. Missing rate limiting

Step 4: Best Practices

Check for security best practices:

  1. Logging of security events
  2. Input validation completeness
  3. Secure defaults
  4. Defense in depth

Output Format

Critical Issues Found (🔴)

🔴 CRITICAL SECURITY ISSUES FOUND

SQL Injection Risk:
- server/routers.ts:45
  Pattern: db.execute(`SELECT * FROM ${table}`)
  Risk: Arbitrary SQL execution
  Fix: Use parameterized queries with Drizzle ORM

Command Injection Risk:
- server/services/file.ts:89
  Pattern: exec(`convert ${userFile}`)
  Risk: Arbitrary command execution
  Fix: Use library instead of shell command

⚠️  DO NOT DEPLOY until these are fixed!

High-Risk Issues (🟠)

🟠 HIGH-RISK SECURITY ISSUES

Broken Access Control:
- server/services/project.ts:34
  Issue: No ownership check before update
  Risk: Users can modify other users' projects
  Fix: Add userId verification

Sensitive Data Exposure:
- server/services/user.ts:23
  Issue: Returning full user object (includes password hash)
  Risk: Password hashes exposed to client
  Fix: Exclude sensitive fields

All Clear

✅ Security Audit Passed

Checked:
✅ SQL Injection: No vulnerabilities
✅ XSS: React auto-escaping in place
✅ Authentication: All sensitive routes protected
✅ Access Control: Ownership checks present
✅ Data Exposure: Sensitive fields excluded
✅ Configuration: Security headers enabled
✅ Logging: Security events logged

No critical or high-risk issues found.

Checklist

Before Every Deployment

  • No SQL injection patterns
  • No command injection patterns
  • All sensitive procedures use protectedProcedure
  • User objects exclude password fields
  • CORS configured for specific origins
  • Security headers enabled (Helmet)
  • No hardcoded secrets in code
  • Access control checks present
  • Rate limiting on auth endpoints
  • Security events logged

Monthly Security Review

  • Review recent security incidents
  • Update vulnerability patterns
  • Check for new OWASP guidelines
  • Audit dependencies for vulnerabilities
  • Review access control logic
  • Test authentication flows
  • Review logging coverage

Integration

CI/CD Pipeline

Add to GitHub Actions:

- name: Security Audit
  run: |
    npm audit --audit-level=moderate
    # Run security-auditor skill via Claude

Pre-Deployment Checklist

Always run before deploying to production:

  1. Security-auditor skill
  2. npm audit
  3. Dependency vulnerability scan
  4. Manual review of auth/access control changes

Examples

Example 1: SQL Injection Found

🔴 CRITICAL: SQL Injection Vulnerability

Location: server/services/search.ts:45
Code:
  const query = `SELECT * FROM projects WHERE name LIKE '%${searchTerm}%'`;
  return await db.execute(query);

Risk: HIGH - Arbitrary SQL execution possible
Impact: Full database access, data theft, data destruction

Fix:
  const results = await db.select()
    .from(projects)
    .where(like(projects.name, `%${searchTerm}%`));

Example 2: Missing Access Control

🟠 HIGH: Broken Access Control

Location: server/services/project.ts:78
Code:
  export async function deleteProject(id: string) {
    return await db.delete(projects).where(eq(projects.id, id));
  }

Risk: MEDIUM - Users can delete other users' projects
Impact: Data loss, unauthorized modifications

Fix:
  export async function deleteProject(id: string, userId: string) {
    const project = await getById(id);
    if (project.userId !== userId) {
      throw new TRPCError({ code: 'FORBIDDEN' });
    }
    return await db.delete(projects).where(eq(projects.id, id));
  }

Example 3: All Clear

✅ Security Audit Complete

Files Scanned: 47
Patterns Checked: 25
Issues Found: 0

Security Status: GOOD
Ready for deployment ✅

Resources


This skill provides a first line of defense against common security vulnerabilities. It's not a replacement for penetration testing, but catches most issues before they reach production.