| name | security-review-owasp |
| description | Comprehensive security review covering OWASP Top 10 2025, OWASP Agentic AI Top 10 2026, secrets detection, input validation, authentication/authorization, and language-specific security patterns. |
| tags | ["security","owasp","vulnerability","secrets","auth","input-validation","code-review"] |
| version | 1.0.0 |
| author | Enhanced from OWASP Agentic Skills + agamm/claude-code-owasp) |
Security Review - OWASP Enhanced
Overview
Comprehensive security review that scans code and architecture against:
- OWASP Top 10:2025 - Web application security risks
- OWASP Agentic AI Top 10:2026 - AI agent security risks
- OWASP ASVS 5.0 - Application Security Verification Standard
- Secrets detection - API keys, tokens, credentials
- Input validation - Injection attacks, XSS, CSRF
- Authentication/Authorization - Access control, session management
- Language-specific patterns - 20+ language security quirks
This enhanced version uses parallel specialized agents for comprehensive coverage.
When to Use
Always use before:
- Committing code to main branch
- Creating pull requests
- Deploying to production
- Releasing new versions
- Adding authentication/authorization
- Handling user input
- Integrating third-party APIs
- Processing sensitive data
Use during:
- Code review process
- Security audits
- Penetration testing prep
- Compliance reviews (SOC2, ISO 27001)
The 4-Phase Security Review Process
┌─────────────────────────────────────────────────────────┐
│ SECURITY REVIEW WORKFLOW │
└─────────────────────────────────────────────────────────┘
┌──────────────┐
│ PHASE 1 │ Static Analysis
│ STATIC │ - OWASP Top 10 scan
│ ANALYSIS │ - Secrets detection
└──────┬───────┘ - Code patterns
│
▼
┌──────────────┐
│ PHASE 2 │ Dynamic Analysis
│ DYNAMIC │ - Runtime behavior
│ ANALYSIS │ - API testing
└──────┬───────┘ - Auth flows
│
▼
┌──────────────┐
│ PHASE 3 │ Architecture Review
│ ARCHITECTURE │ - Design patterns
│ REVIEW │ - Data flow
└──────┬───────┘ - Trust boundaries
│
▼
┌──────────────┐
│ PHASE 4 │ Report & Remediate
│ REPORT & │ - Findings summary
│ REMEDIATE │ - Fix recommendations
└──────────────┘ - Verification
OWASP Top 10:2025 Coverage
A01:2025 - Broken Access Control
What to check:
Common vulnerabilities:
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json(user);
});
app.get('/api/users/:id', requireAuth, async (req, res) => {
const userId = req.params.id;
if (req.user.id !== userId && !req.user.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
const user = await db.users.findById(userId);
res.json(user);
});
Automated checks:
grep -r "app\.(get|post|put|delete)" src/ | grep -v "requireAuth\|isAuthenticated"
A02:2025 - Cryptographic Failures
What to check:
Common vulnerabilities:
import crypto from 'crypto';
const cipher = crypto.createCipher('aes-128-ecb', 'hardcoded-key');
import crypto from 'crypto';
const algorithm = 'aes-256-gcm';
const key = Buffer.from(process.env.ENCRYPTION_KEY!, 'hex');
const iv = crypto.randomBytes(16);
function encrypt(text: string): string {
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
}
Automated checks:
grep -r "createCipher\|md5\|sha1\|des\|rc4" src/
grep -r "key.*=.*['\"]" src/ | grep -v "process.env"
A03:2025 - Injection
What to check:
Common vulnerabilities:
app.get('/api/users', async (req, res) => {
const name = req.query.name;
const sql = `SELECT * FROM users WHERE name = '${name}'`;
const users = await db.query(sql);
res.json(users);
});
app.get('/api/users', async (req, res) => {
const name = req.query.name;
const users = await db.query(
'SELECT * FROM users WHERE name = $1',
[name]
);
res.json(users);
});
const { exec } = require('child_process');
app.post('/api/convert', (req, res) => {
const filename = req.body.filename;
exec(`convert ${filename} output.pdf`, (err, stdout) => {
res.send(stdout);
});
});
const sharp = require('sharp');
app.post('/api/convert', async (req, res) => {
const filename = req.body.filename;
if (!/^[a-zA-Z0-9_-]+\.(jpg|png)$/.test(filename)) {
return res.status(400).json({ error: 'Invalid filename' });
}
await sharp(filename).toFile('output.pdf');
res.json({ success: true });
});
Automated checks:
grep -r "query.*\${.*}" src/
grep -r "query.*\+.*req\." src/
grep -r "exec\|spawn\|execSync" src/
A04:2025 - Insecure Design
What to check:
Common issues:
app.post('/api/transfer', async (req, res) => {
const { from, to, amount } = req.body;
await transferMoney(from, to, amount);
res.json({ success: true });
});
app.post('/api/transfer', requireAuth, async (req, res) => {
const { to, amount } = req.body;
const from = req.user.id;
const balance = await getBalance(from);
if (balance < amount) {
return res.status(400).json({ error: 'Insufficient funds' });
}
if (amount > MAX_TRANSFER_AMOUNT) {
return res.status(400).json({ error: 'Amount exceeds limit' });
}
await db.transaction(async (trx) => {
await debit(from, amount, trx);
await credit(to, amount, trx);
await logTransfer(from, to, amount, trx);
});
res.json({ success: true });
});
A05:2025 - Security Misconfiguration
What to check:
Common issues:
app.use((err, req, res, next) => {
res.status(500).json({
error: err.message,
stack: err.stack,
query: req.query,
body: req.body
});
});
app.use((err, req, res, next) => {
logger.error('Request failed', {
error: err.message,
stack: err.stack,
url: req.url,
method: req.method
});
res.status(500).json({
error: 'Internal server error',
requestId: req.id
});
});
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
Automated checks:
npm audit
curl -I https://your-app.com | grep -i "x-frame-options\|x-content-type\|strict-transport"
A06:2025 - Vulnerable and Outdated Components
What to check:
Automated checks:
npm audit
npm audit fix
npx snyk test
npm outdated
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
A07:2025 - Identification and Authentication Failures
What to check:
Common vulnerabilities:
function validatePassword(password: string): boolean {
return password.length >= 6;
}
function validatePassword(password: string): boolean {
const minLength = 12;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
return (
password.length >= minLength &&
hasUpperCase &&
hasLowerCase &&
hasNumbers &&
hasSpecialChar
);
}
app.post('/api/login', async (req, res) => {
const { email, password } = req.body;
const user = await authenticateUser(email, password);
if (user) {
res.json({ token: generateToken(user) });
} else {
res.status(401).json({ error: 'Invalid credentials' });
}
});
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
message: 'Too many login attempts, please try again later'
});
app.post('/api/login', loginLimiter, async (req, res) => {
const { email, password } = req.body;
const user = await authenticateUser(email, password);
if (user) {
res.json({ token: generateToken(user) });
} else {
res.status(401).json({ error: 'Invalid credentials' });
}
});
A08:2025 - Software and Data Integrity Failures
What to check:
Common vulnerabilities:
app.post('/api/data', (req, res) => {
const data = eval(req.body.serialized);
res.json(data);
});
import { z } from 'zod';
const DataSchema = z.object({
id: z.string().uuid(),
name: z.string().max(100),
value: z.number().min(0).max(1000)
});
app.post('/api/data', (req, res) => {
try {
const data = DataSchema.parse(req.body);
res.json(data);
} catch (error) {
res.status(400).json({ error: 'Invalid data format' });
}
});
A09:2025 - Security Logging and Monitoring Failures
What to check:
Implementation:
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'security.log' })
]
});
app.post('/api/login', async (req, res) => {
const { email, password } = req.body;
const user = await authenticateUser(email, password);
if (user) {
logger.info('Login successful', {
userId: user.id,
email: user.email,
ip: req.ip,
userAgent: req.get('user-agent'),
timestamp: new Date().toISOString()
});
res.json({ token: generateToken(user) });
} else {
logger.warn('Login failed', {
email: email,
ip: req.ip,
userAgent: req.get('user-agent'),
timestamp: new Date().toISOString()
});
res.status(401).json({ error: 'Invalid credentials' });
}
});
function requireAdmin(req, res, next) {
if (!req.user.isAdmin) {
logger.warn('Unauthorized access attempt', {
userId: req.user.id,
resource: req.path,
method: req.method,
ip: req.ip,
timestamp: new Date().toISOString()
});
return res.status(403).json({ error: 'Forbidden' });
}
next();
}
A10:2025 - Server-Side Request Forgery (SSRF)
What to check:
Common vulnerabilities:
app.post('/api/fetch', async (req, res) => {
const url = req.body.url;
const response = await fetch(url);
const data = await response.text();
res.send(data);
});
import { URL } from 'url';
const ALLOWED_DOMAINS = ['api.example.com', 'cdn.example.com'];
const BLOCKED_IPS = ['127.0.0.1', '0.0.0.0', '169.254.169.254'];
function isUrlSafe(urlString: string): boolean {
try {
const url = new URL(urlString);
if (url.protocol !== 'https:') {
return false;
}
if (!ALLOWED_DOMAINS.includes(url.hostname)) {
return false;
}
if (BLOCKED_IPS.includes(url.hostname)) {
return false;
}
if (/^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)/.test(url.hostname)) {
return false;
}
return true;
} catch {
return false;
}
}
app.post('/api/fetch', async (req, res) => {
const url = req.body.url;
if (!isUrlSafe(url)) {
return res.status(400).json({ error: 'Invalid URL' });
}
const response = await fetch(url, {
redirect: 'manual',
timeout: 5000
});
const data = await response.text();
res.send(data);
});
OWASP Agentic AI Top 10:2026
A01:2026 - Prompt Injection / Goal Hijacking
What to check:
Common vulnerabilities:
async function chatWithAI(userMessage: string) {
const prompt = `You are a helpful assistant. User says: ${userMessage}`;
return await llm.complete(prompt);
}
async function chatWithAI(userMessage: string) {
const systemPrompt = "You are a helpful assistant.";
const messages = [
{ role: "system", content: systemPrompt },
{ role: "user", content: userMessage }
];
return await llm.chat(messages);
}
A02:2026 - Tool Poisoning
What to check:
Implementation:
interface Tool {
name: string;
description: string;
parameters: z.ZodSchema;
execute: (params: any) => Promise<any>;
permissions: string[];
}
class ToolRegistry {
private tools = new Map<string, Tool>();
register(tool: Tool) {
if (!tool.name || !tool.execute) {
throw new Error('Invalid tool definition');
}
if (tool.name.includes('eval') || tool.name.includes('exec')) {
throw new Error('Dangerous tool name');
}
this.tools.set(tool.name, tool);
}
async execute(toolName: string, params: any, userPermissions: string[]) {
const tool = this.tools.get(toolName);
if (!tool) {
throw new Error('Tool not found');
}
const hasPermission = tool.permissions.every(p =>
userPermissions.includes(p)
);
if (!hasPermission) {
throw new Error('Insufficient permissions');
}
const validatedParams = tool.parameters.parse(params);
return await this.sandbox(tool.execute, validatedParams);
}
private async sandbox(fn: Function, params: any) {
return await fn(params);
}
}
A03:2026 - MCP Exploits
What to check:
A04:2026 - Privilege Abuse
What to check:
A05:2026 - Skill Injection
What to check:
A06:2026 - Unsafe Skill Execution
What to check:
A07:2026 - Agent Hijacking
What to check:
A08:2026 - Rogue Agents
What to check:
A09:2026 - Data Leakage
What to check:
A10:2026 - Insufficient Monitoring
What to check:
Secrets Detection
Tools to use:
trufflehog git file://. --only-verified
ggshield secret scan path .
gitleaks detect --source . --verbose
grep -r "api[_-]key\|secret\|password\|token" src/ | grep -v "process.env"
Common patterns to detect:
- AWS keys:
AKIA[0-9A-Z]{16}
- GitHub tokens:
ghp_[a-zA-Z0-9]{36}
- Slack tokens:
xox[baprs]-[0-9a-zA-Z-]{10,}
- Private keys:
-----BEGIN.*PRIVATE KEY-----
- Database URLs:
postgres://.*:.*@
Language-Specific Security Patterns
JavaScript/TypeScript
Python
Go
Rust
Automated Security Scanning
Run all security checks:
#!/bin/bash
echo "🔍 Running security scans..."
echo "📦 Checking dependencies..."
npm audit --audit-level=moderate
echo "🔐 Scanning for secrets..."
trufflehog git file://. --only-verified
echo "🔬 Running static analysis..."
npx eslint-plugin-security
echo "🛡️ OWASP dependency check..."
npx dependency-check --project . --scan .
echo "🐳 Scanning containers..."
trivy image your-image:latest
echo "☁️ Scanning IaC..."
checkov -d .
echo "📜 Checking licenses..."
npx license-checker --summary
echo "✅ Security scan complete!"
Security Review Checklist
Before committing:
Before deploying:
Remediation Priority
Critical (Fix immediately):
- SQL injection
- Authentication bypass
- Secrets in code
- Remote code execution
- Privilege escalation
High (Fix within 24 hours):
- XSS vulnerabilities
- CSRF vulnerabilities
- Insecure deserialization
- Broken access control
- Cryptographic failures
Medium (Fix within 1 week):
- Security misconfiguration
- Outdated dependencies
- Missing security headers
- Insufficient logging
- Weak password policy
Low (Fix when convenient):
- Information disclosure
- Missing rate limiting
- Verbose error messages
- Outdated documentation
Integration with CI/CD
GitHub Actions example:
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Run TruffleHog
uses: trufflesecurity/trufflehog@main
with:
path: ./
- name: Run OWASP Dependency Check
uses: dependency-check/Dependency-Check_Action@main
Related Skills
requesting-code-review - Pre-commit review workflow
github-pr-workflow - PR creation with security checks
tdd-iron-law - Test security requirements
Remember: Security is not a feature. It's a requirement. Every line of code is a potential vulnerability. Review early, review often.