Skip to content

Security Reviewer Guide: Usage, Examples, and Best Practices for Beginners

Purpose

This post demonstrates how to use the Security Reviewer skill in Claude Code to find and fix security issues in your code.

Environment

  • Claude Code CLI
  • claude-skills plugin
  • Security Reviewer skill
  • Any programming language

What is Security Reviewer?

Security Reviewer is a skill in the claude-skills plugin that helps you find security vulnerabilities in your code before you commit it. It checks for common security issues like:

  • Hardcoded secrets (API keys, passwords)
  • SQL injection vulnerabilities
  • XSS (Cross-Site Scripting) issues
  • Missing authentication/authorization
  • Input validation problems
  • Insecure error handling

When should you use it? You should run Security Reviewer before any commit, especially when:

  • Adding authentication features
  • Handling user input
  • Working with databases
  • Processing file uploads
  • Implementing payment/sensitive features

Installation and Setup

First, install the claude-skills plugin if you haven’t already:

Terminal window
npm install -g @jeffallan/claude-skills

Then, activate the Security Reviewer skill in your Claude Code session:

Terminal window
claude skill activate security-reviewer

You can verify it’s available by asking Claude:

Terminal window
@claude What skills do you have available?

Core Usage Patterns

The easiest way to use Security Reviewer is to ask Claude directly:

Use security-reviewer to check this code

Or use the skill command:

/security-reviewer

Claude will analyze your current code and find security issues. You can also be more specific:

Use security-reviewer to check auth.ts for authentication issues
Run security-reviewer on my API endpoints

Example 1: Authentication Code

I’m building a login feature and want to check it for security issues. Here’s my code:

auth.ts
export async function login(username: string, password: string) {
const user = await db.query(
`SELECT * FROM users WHERE username = '${username}'`
)
if (user.password === password) {
return generateToken(user.id)
}
throw new Error('Invalid credentials')
}

I ask Claude to review it:

Use security-reviewer to check auth.ts

Security Reviewer finds two critical issues:

  1. SQL Injection: The query interpolates username directly, allowing attackers to manipulate the SQL.

  2. Plaintext Password Comparison: Passwords are stored in plaintext, which is a major security vulnerability.

Here’s the fixed version:

auth.ts
export async function login(username: string, password: string) {
// Use parameterized query to prevent SQL injection
const user = await db.query(
'SELECT * FROM users WHERE username = $1',
[username]
)
if (!user) {
throw new Error('Invalid credentials')
}
// Compare hashed passwords
const isValid = await bcrypt.compare(password, user.password_hash)
if (!isValid) {
throw new Error('Invalid credentials')
}
return generateToken(user.id)
}

Example 2: Input Validation

I’m creating an API endpoint that accepts user input. Let me check it:

api.ts
import express from 'express'
const app = express()
app.get('/search', (req, res) => {
const query = req.query.q
const results = db.query(
`SELECT * FROM products WHERE name LIKE '%${query}%'`
)
res.json(results)
})

When I run security-reviewer on this code, it flags:

  1. SQL Injection: The query parameter is interpolated into the SQL query.

  2. No Input Validation: No validation on the q parameter.

  3. No Rate Limiting: The endpoint is vulnerable to abuse.

Here’s the secure version:

api.ts
import express from 'express'
import rateLimit from 'express-rate-limit'
import { z } from 'zod'
const app = express()
// Add rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
})
app.use('/search', limiter)
// Validate input
const searchSchema = z.object({
q: z.string().min(1).max(100).regex(/^[a-zA-Z0-9\s]+$/)
})
app.get('/search', async (req, res) => {
// Validate input
const { q } = searchSchema.parse(req.query)
// Use parameterized query
const results = await db.query(
'SELECT * FROM products WHERE name LIKE $1',
[`%${q}%`]
)
res.json(results)
})

Example 3: Hardcoded Secrets

I accidentally committed an API key in my code:

config.ts
export const API_KEY = "sk-proj-abc123xyz456"
export async function callExternalAPI(data: any) {
const response = await fetch('https://api.example.com/endpoint', {
headers: {
'Authorization': `Bearer ${API_KEY}`
},
body: JSON.stringify(data)
})
return response.json()
}

When I run security-reviewer, it immediately flags the hardcoded API key. The fix:

config.ts
export async function callExternalAPI(data: any) {
const apiKey = process.env.API_KEY
if (!apiKey) {
throw new Error('API_KEY not configured')
}
const response = await fetch('https://api.example.com/endpoint', {
headers: {
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify(data)
})
return response.json()
}

Best Practices

DO

  • Run security-reviewer before every commit
  • Fix CRITICAL and HIGH issues immediately
  • Use environment variables for secrets
  • Validate all user input with a schema library (Zod, Joi)
  • Use parameterized queries for database operations
  • Sanitize HTML output to prevent XSS
  • Implement rate limiting on public endpoints
  • Hash passwords with bcrypt/argon2
  • Use HTTPS in production
  • Keep dependencies updated

DON’T

  • Don’t commit before running security-reviewer
  • Don’t ignore CRITICAL or HIGH severity issues
  • Don’t hardcode secrets in your code
  • Don’t trust user input without validation
  • Don’t build SQL queries with string interpolation
  • Don’t store passwords in plaintext
  • Don’t leak sensitive data in error messages
  • Don’t skip security checks for “internal” APIs

Integration with Development Workflow

Security Reviewer works best when integrated into your workflow:

Write code → Run security-reviewer → Fix issues → Commit

You can also use it with other claude-skills:

  • tdd-guide: Write tests first, then run security-reviewer
  • code-reviewer: Get general code quality feedback after security checks
  • planner: Plan secure features from the start

For example:

Use tdd-guide to implement user authentication, then use security-reviewer to check it

Common Issues and Solutions

Issue: False Positives

Sometimes security-reviewer flags code that’s actually safe. For example, using environment variables might trigger a “hardcoded secret” warning if the pattern isn’t recognized.

Solution: Review the issue carefully. If it’s truly safe, document why in a comment.

Issue: Too Many Warnings

A large codebase might have hundreds of security issues.

Solution: Prioritize CRITICAL and HIGH issues first. Use filters to focus on specific files or types of vulnerabilities.

Issue: Performance on Large Codebases

Running security-reviewer on a huge codebase can be slow.

Solution: Run it on specific directories or files:

Use security-reviewer to check the auth/ directory
  • security-review: Core security checking (this skill)
  • tdd-guide: Test-driven development workflow
  • code-reviewer: General code quality review
  • planner: Plan secure features before implementation

Summary

In this post, I showed how to use Security Reviewer in Claude Code to find and fix security vulnerabilities. The key points are:

  • Run security-reviewer before every commit
  • Fix CRITICAL and HIGH issues immediately
  • Never hardcode secrets
  • Always validate user input
  • Use parameterized queries for databases

Security Reviewer helps you catch vulnerabilities early, before they reach production. It’s not a replacement for security expertise, but it’s an excellent first line of defense for developers at any level.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments