Loading...
Loading...
Scans code for security vulnerabilities including injection attacks, authentication flaws, exposed secrets, insecure dependencies, and data exposure. Use when the user says "security review", "is this secure?", "check for vulnerabilities", "audit this", or before deploying to production.
npx skill4agent add aakash-dhar/claude-skills security-audit# Search for common secret patterns
grep -rn "password\|secret\|api_key\|apikey\|token\|private_key\|AWS_SECRET\|DATABASE_URL" --include="*.ts" --include="*.js" --include="*.py" --include="*.env" --include="*.json" --include="*.yaml" --include="*.yml" .
# Check for .env files committed
git ls-files | grep -i "\.env"
# Check git history for secrets
git log --all --diff-filter=D -- "*.env" "*.pem" "*.key".gitignore.env*.pem*.key*.p12.env.example// 🔴 VULNERABLE — string concatenation in query
const user = await db.query(`SELECT * FROM users WHERE id = '${req.params.id}'`);
// ✅ SAFE — parameterized query
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);// 🔴 VULNERABLE — user input directly in query object
const user = await User.find({ username: req.body.username });
// ✅ SAFE — explicitly cast to string
const user = await User.find({ username: String(req.body.username) });// 🔴 VULNERABLE — user input in shell command
exec(`convert ${req.body.filename} output.png`);
// ✅ SAFE — use execFile with arguments array
execFile('convert', [sanitizedFilename, 'output.png']);// 🔴 VULNERABLE — unsanitized HTML rendering
element.innerHTML = userInput;
// React: dangerouslySetInnerHTML={{ __html: userInput }}
// ✅ SAFE — use textContent or sanitize
element.textContent = userInput;
// React: use DOMPurify.sanitize() before dangerouslySetInnerHTML// 🔴 VULNERABLE — user controls file path
const file = fs.readFileSync(`./uploads/${req.params.filename}`);
// ✅ SAFE — resolve and validate path stays within allowed directory
const safePath = path.resolve('./uploads', req.params.filename);
if (!safePath.startsWith(path.resolve('./uploads'))) throw new Error('Invalid path');// 🔴 VULNERABLE — IDOR: no ownership check
app.get('/api/orders/:id', async (req, res) => {
const order = await Order.findById(req.params.id);
res.json(order);
});
// ✅ SAFE — verify ownership
app.get('/api/orders/:id', async (req, res) => {
const order = await Order.findById(req.params.id);
if (order.userId !== req.user.id) return res.status(403).json({ error: 'Forbidden' });
res.json(order);
});Access-Control-Allow-Origin: *// 🔴 VULNERABLE — leaking sensitive fields
res.json(user);
// ✅ SAFE — explicit field selection
res.json({
id: user.id,
name: user.name,
email: user.email,
});# Node.js
npm audit
# or
npx better-npm-audit audit
# Python
pip audit
# or
safety check
# Check for outdated packages
npm outdated
pip list --outdatedContent-Security-PolicyStrict-Transport-SecurityX-Content-Type-Options: nosniffX-Frame-Options: DENYReferrer-PolicyPermissions-Policy# Check response headers
curl -I https://your-app.comalg: none// 🔴 VULNERABLE — predictable token
const token = Math.random().toString(36);
// ✅ SAFE — cryptographically secure
const token = crypto.randomBytes(32).toString('hex');express.json({ limit: '10kb' })eval()Function()vm.runInNewContext()DEBUG = FalseALLOWED_HOSTS['*']SECRET_KEY@login_requiredyaml.load()Loader=SafeLoaderSECURE_SSL_REDIRECTSESSION_COOKIE_SECURECSRF_COOKIE_SECUREapp.secret_key@login_requiredflask-talismanflask-limitersecure_filename()dangerouslySetInnerHTMLNEXT_PUBLIC_getServerSidePropspagePropsnext.config.jsv-htmlnuxt.configuseAsyncDatauseFetchconfig.force_ssl = truehtml_saferawprotect_from_forgerystrong_parametershas_secure_passwordsend()constantize()config.filter_parametersfmt.Sprintfhttp.ServeFileos.Opencrypto/randmath/randpermitAll()@Query@Validapplication.propertiesapplication.ymlAPP_DEBUG=false.enveval()exec()system()Auth::check()mass assignment$fillable$guarded{!! !!}"Action": "*""Resource": "*".dockerignore.env.gitnode_modules// vulnerable code
...
// fixed code
...