
Security Testing
- 548 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
security-testing is a Claude Code skill that guides SAST, DAST, dependency scanning, and OWASP Top 10 checks for developers who need to find web application vulnerabilities before shipping.
About
security-testing is a security agent skill from aj-geddes/useful-ai-prompts that structures vulnerability discovery through static analysis, dynamic analysis, penetration testing workflows, and dependency scanning. It activates on security test, OWASP, SQL injection, XSS, CSRF, and penetration testing requests, helping agents surface common web flaws and third-party package risks before production. Developers invoke security-testing during pre-release hardening when automated scanners and manual test plans must align with OWASP guidance and data-protection requirements. The skill packages reference guides and best practices so agents produce actionable findings instead of generic security reminders.
- Combines SAST, DAST, dependency scanning and penetration testing in one agent skill
- Covers OWASP Top 10, SQL injection, XSS, CSRF, authentication flaws and sensitive data exposure
- Runs automated scans plus guided manual validation steps
- Produces prioritized vulnerability reports with severity levels
- Hard-gate: never ship code that fails critical or high severity checks
Security Testing by the numbers
- 548 all-time installs (skills.sh)
- Ranked #499 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill security-testingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 548 |
|---|---|
| repo stars | ★ 305 |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you run OWASP security tests before shipping a web app?
Automatically surface OWASP Top 10 issues, dependency vulnerabilities, and common web flaws before shipping.
Who is it for?
Developers preparing web applications for release who need agent-driven SAST, DAST, dependency scans, and OWASP Top 10 coverage.
Skip if: Production incident response, compliance certification projects alone, or teams already running a fully automated CI security pipeline without agent assistance.
When should I use this skill?
The user requests security testing, vulnerability scanning, OWASP review, penetration testing, or SQL injection and XSS checks.
What you get
Vulnerability findings list, SAST and DAST scan notes, dependency audit results, and remediation guidance.
- Vulnerability report
- Scan command outputs
- Remediation checklist
By the numbers
- Targets OWASP Top 10 vulnerability categories
Files
Security Testing
Table of Contents
Overview
Security testing identifies vulnerabilities, weaknesses, and threats in applications to ensure data protection, prevent unauthorized access, and maintain system integrity. It combines automated scanning (SAST, DAST) with manual penetration testing and code review.
When to Use
- Testing for OWASP Top 10 vulnerabilities
- Scanning dependencies for known vulnerabilities
- Testing authentication and authorization
- Validating input sanitization
- Testing API security
- Checking for sensitive data exposure
- Validating security headers
- Testing session management
Quick Start
Minimal working example:
# security_scan.py
from zapv2 import ZAPv2
import time
class SecurityScanner:
def __init__(self, target_url, api_key=None):
self.zap = ZAPv2(apikey=api_key, proxies={
'http': 'http://localhost:8080',
'https': 'http://localhost:8080'
})
self.target = target_url
def scan(self):
"""Run full security scan."""
print(f"Scanning {self.target}...")
# Spider the application
print("Spidering...")
scan_id = self.zap.spider.scan(self.target)
while int(self.zap.spider.status(scan_id)) < 100:
time.sleep(2)
print(f"Spider progress: {self.zap.spider.status(scan_id)}%")
# Active scan
print("Running active scan...")
// ... (see reference guides for full implementation)Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| OWASP ZAP (DAST) | OWASP ZAP (DAST) |
| SQL Injection Testing | SQL Injection Testing |
| XSS Testing | XSS Testing |
| Authentication & Authorization Testing | Authentication & Authorization Testing |
| CSRF Protection Testing | CSRF Protection Testing |
| Dependency Vulnerability Scanning | Dependency Vulnerability Scanning |
| Security Headers Testing | Security Headers Testing |
| Secrets Detection | Secrets Detection |
Best Practices
✅ DO
- Run security scans in CI/CD
- Test with real attack vectors
- Scan dependencies regularly
- Use security headers
- Implement rate limiting
- Validate and sanitize all input
- Use parameterized queries
- Test authentication/authorization thoroughly
❌ DON'T
- Store secrets in code
- Trust user input
- Expose detailed error messages
- Skip dependency updates
- Use default credentials
- Ignore security warnings
- Test only happy paths
- Commit sensitive data
Authentication & Authorization Testing
Authentication & Authorization Testing
// tests/security/auth.test.ts
describe("Authentication Security", () => {
test("should reject weak passwords", async () => {
const weakPasswords = [
"password",
"12345678",
"qwerty",
"abc123",
"password123",
];
for (const password of weakPasswords) {
const response = await request(app).post("/api/users").send({
email: "test@example.com",
password,
});
expect(response.status).toBe(400);
expect(response.body.error).toMatch(
/password.*weak|password.*requirements/i,
);
}
});
test("should rate limit login attempts", async () => {
const credentials = {
email: "test@example.com",
password: "wrongpassword",
};
// Try 10 failed logins
for (let i = 0; i < 10; i++) {
await request(app).post("/api/auth/login").send(credentials);
}
// 11th attempt should be rate limited
const response = await request(app)
.post("/api/auth/login")
.send(credentials);
expect(response.status).toBe(429);
expect(response.body.error).toMatch(/too many attempts|rate limit/i);
});
test("should prevent unauthorized access", async () => {
const response = await request(app).get("/api/admin/users").expect(401);
});
test("should prevent privilege escalation", async () => {
const regularUserToken = await getRegularUserToken();
const response = await request(app)
.delete("/api/users/999") // Try to delete another user
.set("Authorization", `Bearer ${regularUserToken}`)
.expect(403);
});
test("JWT tokens should expire", async () => {
// Create expired token
const expiredToken = jwt.sign({ userId: "123" }, JWT_SECRET, {
expiresIn: "-1s",
});
const response = await request(app)
.get("/api/protected")
.set("Authorization", `Bearer ${expiredToken}`)
.expect(401);
});
});CSRF Protection Testing
CSRF Protection Testing
# tests/security/test_csrf.py
import pytest
from flask import session
class TestCSRFProtection:
def test_post_without_csrf_token_rejected(self, client):
"""POST requests without CSRF token should be rejected."""
response = client.post('/api/users', json={
'email': 'test@example.com',
'name': 'Test'
})
assert response.status_code == 403
assert 'CSRF' in response.json['error']
def test_post_with_invalid_csrf_token_rejected(self, client):
"""POST with invalid CSRF token should be rejected."""
response = client.post('/api/users',
json={'email': 'test@example.com'},
headers={'X-CSRF-Token': 'invalid-token'}
)
assert response.status_code == 403
def test_post_with_valid_csrf_token_accepted(self, client):
"""POST with valid CSRF token should be accepted."""
# Get CSRF token
response = client.get('/api/csrf-token')
csrf_token = response.json['csrfToken']
# Use token in POST
response = client.post('/api/users',
json={'email': 'test@example.com', 'name': 'Test'},
headers={'X-CSRF-Token': csrf_token}
)
assert response.status_code == 201Dependency Vulnerability Scanning
Dependency Vulnerability Scanning
# Run npm audit
npm audit
# Fix vulnerabilities
npm audit fix
# For Python - Safety
pip install safety
safety check
# For Java - OWASP Dependency Check
mvn org.owasp:dependency-check-maven:check# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
dependency-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run npm audit
run: npm audit --audit-level=high
- name: Run Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
sast-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/security-audit
p/owasp-top-ten
dast-scan:
runs-on: ubuntu-latest
steps:
- name: ZAP Scan
uses: zaproxy/action-baseline@v0.7.0
with:
target: "http://localhost:3000"OWASP ZAP (DAST)
OWASP ZAP (DAST)
# security_scan.py
from zapv2 import ZAPv2
import time
class SecurityScanner:
def __init__(self, target_url, api_key=None):
self.zap = ZAPv2(apikey=api_key, proxies={
'http': 'http://localhost:8080',
'https': 'http://localhost:8080'
})
self.target = target_url
def scan(self):
"""Run full security scan."""
print(f"Scanning {self.target}...")
# Spider the application
print("Spidering...")
scan_id = self.zap.spider.scan(self.target)
while int(self.zap.spider.status(scan_id)) < 100:
time.sleep(2)
print(f"Spider progress: {self.zap.spider.status(scan_id)}%")
# Active scan
print("Running active scan...")
scan_id = self.zap.ascan.scan(self.target)
while int(self.zap.ascan.status(scan_id)) < 100:
time.sleep(5)
print(f"Scan progress: {self.zap.ascan.status(scan_id)}%")
return self.get_results()
def get_results(self):
"""Get scan results."""
alerts = self.zap.core.alerts(baseurl=self.target)
# Group by risk level
results = {
'high': [],
'medium': [],
'low': [],
'informational': []
}
for alert in alerts:
risk = alert['risk'].lower()
results[risk].append({
'name': alert['alert'],
'description': alert['description'],
'solution': alert['solution'],
'url': alert['url'],
'param': alert.get('param', ''),
'evidence': alert.get('evidence', '')
})
return results
def report(self, results):
"""Generate security report."""
print("\n" + "="*60)
print("SECURITY SCAN RESULTS")
print("="*60)
for risk_level in ['high', 'medium', 'low', 'informational']:
issues = results[risk_level]
if issues:
print(f"\n{risk_level.upper()} Risk Issues: {len(issues)}")
for issue in issues[:5]: # Show first 5
print(f" - {issue['name']}")
print(f" URL: {issue['url']}")
if issue['param']:
print(f" Parameter: {issue['param']}")
# Fail if high risk found
if results['high']:
raise Exception(f"Found {len(results['high'])} HIGH risk vulnerabilities!")
# Usage
scanner = SecurityScanner('http://localhost:3000')
results = scanner.scan()
scanner.report(results)Secrets Detection
Secrets Detection
# Install detect-secrets
pip install detect-secrets
# Scan repository
detect-secrets scan --all-files --force-use-all-plugins
# Check for hardcoded secrets
git secrets --scan
# TruffleHog for git history
trufflehog git https://github.com/user/repo --only-verifiedSecurity Headers Testing
Security Headers Testing
// tests/security/headers.test.ts
test.describe("Security Headers", () => {
test("should have required security headers", async () => {
const response = await request(app).get("/");
expect(response.headers).toMatchObject({
"x-frame-options": "DENY",
"x-content-type-options": "nosniff",
"x-xss-protection": "1; mode=block",
"strict-transport-security": expect.stringMatching(/max-age=/),
"content-security-policy": expect.any(String),
});
});
test("should not expose sensitive headers", async () => {
const response = await request(app).get("/");
expect(response.headers["x-powered-by"]).toBeUndefined();
expect(response.headers["server"]).not.toMatch(/express|nginx|apache/i);
});
test("CSP should prevent inline scripts", async ({ page }) => {
await page.goto("/");
const cspViolations = [];
page.on("console", (msg) => {
if (
msg.type() === "error" &&
msg.text().includes("Content Security Policy")
) {
cspViolations.push(msg.text());
}
});
// Try to inject inline script
await page.evaluate(() => {
const script = document.createElement("script");
script.textContent = 'alert("test")';
document.body.appendChild(script);
});
expect(cspViolations.length).toBeGreaterThan(0);
});
});SQL Injection Testing
SQL Injection Testing
// tests/security/sql-injection.test.ts
import { test, expect } from "@playwright/test";
import request from "supertest";
import { app } from "../../src/app";
test.describe("SQL Injection Protection", () => {
const sqlInjectionPayloads = [
"' OR '1'='1",
"'; DROP TABLE users; --",
"' UNION SELECT * FROM users --",
"admin'--",
"' OR 1=1--",
"1' AND '1'='1",
];
test("login should prevent SQL injection", async () => {
for (const payload of sqlInjectionPayloads) {
const response = await request(app).post("/api/auth/login").send({
email: payload,
password: payload,
});
// Should return 400/401, not 500 (SQL error)
expect([400, 401]).toContain(response.status);
expect(response.body).not.toMatch(/SQL|syntax|error/i);
}
});
test("search should sanitize input", async () => {
for (const payload of sqlInjectionPayloads) {
const response = await request(app)
.get("/api/products/search")
.query({ q: payload });
// Should not cause SQL error
expect(response.status).toBeLessThan(500);
expect(response.body).not.toMatch(/SQL|syntax/i);
}
});
test("numeric parameters should be validated", async () => {
const response = await request(app)
.get("/api/users/abc") // Non-numeric ID
.expect(400);
expect(response.body.error).toBeTruthy();
});
});XSS Testing
XSS Testing
// tests/security/xss.test.js
describe("XSS Protection", () => {
const xssPayloads = [
'<script>alert("XSS")</script>',
'<img src=x onerror=alert("XSS")>',
'<svg onload=alert("XSS")>',
'javascript:alert("XSS")',
"<iframe src=\"javascript:alert('XSS')\">",
'<body onload=alert("XSS")>',
];
test("user input should be escaped", async () => {
const { page } = await browser.newPage();
for (const payload of xssPayloads) {
await page.goto("/");
// Submit comment with XSS payload
await page.fill('[name="comment"]', payload);
await page.click('[type="submit"]');
// Wait for comment to appear
await page.waitForSelector(".comment");
// Check that script was not executed
const dialogAppeared = await page.evaluate(() => {
return window.xssDetected || false;
});
expect(dialogAppeared).toBe(false);
// Check HTML is escaped
const commentHTML = await page.$eval(".comment", (el) => el.innerHTML);
expect(commentHTML).not.toContain("<script>");
expect(commentHTML).toContain("<script>");
}
});
test("URLs should be validated", async () => {
const response = await request(app)
.post("/api/links")
.send({ url: 'javascript:alert("XSS")' })
.expect(400);
expect(response.body.error).toMatch(/invalid url/i);
});
});#!/bin/bash
# security-checklist.sh - Generate a security review checklist
# Usage: ./security-checklist.sh [--output checklist.md]
set -euo pipefail
OUTPUT="${{1:-/dev/stdout}}"
cat > "$OUTPUT" << 'CHECKLIST'
# Security Review Checklist
## Authentication & Authorization
- [ ] All endpoints require authentication
- [ ] Role-based access control implemented
- [ ] Session management is secure
## Input Validation
- [ ] All user inputs are validated
- [ ] SQL injection prevention
- [ ] XSS prevention
## Data Protection
- [ ] Sensitive data encrypted at rest
- [ ] Sensitive data encrypted in transit
- [ ] PII handling compliant
## TODO: Add domain-specific security checks
CHECKLIST
echo "Checklist generated: $OUTPUT" >&2
Related skills
FAQ
What testing methods does security-testing cover?
security-testing covers SAST, DAST, manual penetration testing workflows, and dependency scanning. Agents use these methods to identify weaknesses threatening data protection and unauthorized access before release.
Which vulnerability classes does security-testing emphasize?
security-testing emphasizes OWASP Top 10 issues including SQL injection, XSS, and CSRF alongside dependency vulnerabilities. Triggers include security test, vulnerability scanning, and penetration testing requests.