| name | audit-security |
| description | Audit code for security vulnerabilities and best practices. Use when reviewing security, checking for vulnerabilities, auditing auth code, or when the user mentions security concerns. Integrates Firecrawl for researching current OWASP guidelines and CVEs, Sentry MCP for checking production security-related errors, and automated codebase scanning.
|
| license | MIT |
Security Audit Skill
Systematic security review for any web application. Research-driven, using current OWASP guidelines.
Step 0: Understand the Project
Before auditing, discover the tech stack and attack surface:
- Read
package.json / requirements.txt / go.mod to identify:
- Auth library (next-auth, passport, supabase-auth, django-auth, etc.)
- Database ORM (Prisma, Sequelize, SQLAlchemy, etc.)
- HTTP framework (Express, Fastify, Django, Flask, etc.)
- Any security-specific packages (helmet, cors, csurf, rate-limit, etc.)
- Identify the auth pattern:
- Session-based vs JWT vs OAuth
- Where tokens are stored (cookies, localStorage, headers)
- How permissions/roles are enforced
- Identify the data flow:
- Where user input enters the system
- How data is validated and sanitized
- How data reaches the database
Step 1: Research Current Threats
Fetch current OWASP and security best practices for the detected stack:
firecrawl:firecrawl_search
{
"query": "<framework> security best practices OWASP <current year>",
"limit": 5,
"sources": [{ "type": "web" }]
}
Scrape the OWASP Top 10 for the relevant platform:
firecrawl:firecrawl_scrape
{
"url": "https://owasp.org/Top10/",
"formats": ["markdown"],
"onlyMainContent": true
}
Also check for known CVEs in dependencies:
firecrawl:firecrawl_search
{
"query": "<package-name> CVE vulnerability <current year>",
"limit": 5,
"sources": [{ "type": "web" }]
}
Step 2: Check Production Security Errors (Sentry)
If Sentry is configured, check for security-related production errors:
sentry:search_issues
{
"organizationSlug": "<ORG_SLUG>",
"query": "401 unauthorized OR 403 forbidden OR CORS OR CSP violation in last 30 days",
"projectSlugOrId": "<PROJECT_SLUG>",
"regionUrl": "<REGION_URL>",
"limit": 20
}
Patterns that indicate security issues:
- Frequent 401/403 errors → possible auth bypass attempts
- CORS errors from unexpected origins → misconfigured CORS
- CSP violations → potential XSS vectors
- Rate limit errors → possible brute force
Step 3: Automated Code Scan
Authentication Audit
Authorization Audit
Input Validation Audit
Data Protection Audit
Security Headers Audit
Dependency Audit
npm audit
pip-audit
cargo audit
govulncheck ./...
bundle audit
Step 4: Common Vulnerability Patterns
SQL Injection
const query = `SELECT * FROM users WHERE id = '${userId}'`;
const query = 'SELECT * FROM users WHERE id = $1';
db.query(query, [userId]);
User.findById(userId);
XSS (Cross-Site Scripting)
<div dangerouslySetInnerHTML={{ __html: userInput }} />
<div>{userInput}</div>
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />
IDOR (Insecure Direct Object Reference)
app.get('/documents/:id', (req, res) => {
const doc = db.documents.findById(req.params.id);
res.json(doc);
});
app.get('/documents/:id', (req, res) => {
const doc = db.documents.findOne({
where: { id: req.params.id, userId: req.user.id }
});
if (!doc) return res.status(404).json({ error: 'Not found' });
res.json(doc);
});
Sensitive Data Exposure
res.json(user);
const { id, name, email, avatar } = user;
res.json({ id, name, email, avatar });
Step 5: Environment and Secrets
Scan for Hardcoded Secrets
Search the codebase for potential leaked secrets. Patterns to look for:
- Generic secret names:
api_key, apiKey, secret, password, token, credentials, private_key
- Key prefixes:
sk-, pk-, ghp_, gho_, xox[bpsa]-, AKIA
- Private key headers:
-----BEGIN (RSA|EC|OPENSSH) PRIVATE KEY-----
Verify .gitignore
.env, .env.local, .env.production
*.pem, *.key, *.p12
credentials.json, service-account.json
.sentryclirc (if it contains auth tokens)
Validate Environment Variables
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
API_KEY: z.string().min(1),
JWT_SECRET: z.string().min(32),
SENTRY_DSN: z.string().url().optional(),
});
const env = envSchema.parse(process.env);
Output: Security Audit Report
## Security Audit: [Project Name]
### Tech Stack
- Framework: [name + version]
- Auth: [library + pattern]
- Database: [ORM + provider]
- Security packages: [list]
### Critical Issues (must fix)
| # | Category | Finding | File | Recommendation |
|---|----------|---------|------|----------------|
| 1 | Auth | JWT secret hardcoded | config.ts:12 | Move to env var |
### High Risk (should fix soon)
| # | Category | Finding | File | Recommendation |
|---|----------|---------|------|----------------|
### Medium Risk (improve when possible)
| # | Category | Finding | File | Recommendation |
|---|----------|---------|------|----------------|
### Passed Checks
- [list of security areas that are properly implemented]
### Dependencies
- Critical CVEs: [count] — [details]
- High CVEs: [count]
- Outdated packages: [count]
### Research Sources
- [URL] — [what it confirmed or revealed]