Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Security auditing and vulnerability assessment specialist. Use when conducting security reviews, analyzing code for vulnerabilities, performing OWASP assessments, or creating security audit reports.
.claude/skills/aiskillstore-security-audit/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-08 | ✗→✓ | ▲ Improved | 37% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 108% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 92% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 49% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 81% | 0% |
Detect common security vulnerabilities during code review and development. Based on OWASP guidelines and common vulnerability patterns.
This skill is framework-generic. It provides universal security patterns:
| Variable | Default | Description | |----------|---------|-------------| | SEVERITY_THRESHOLD | medium | Minimum severity to report | | SCAN_DEPTH | 3 | Directory depth for scanning | | INCLUDE_TESTS | false | Include test files in scan |
MANDATORY - Follow the Workflow steps below in order.
If you're about to:
except: blocksSTOP -> Use parameterized queries -> Add specific exception handling -> Then proceed
./cookbook/sql-injection.md./cookbook/bare-except.md./cookbook/shell-injection.mdBAD - String concatenation:
python# VULNERABLE query = f"SELECT * FROM users WHERE id = {user_id}" cursor.execute(query) query = "SELECT * FROM users WHERE name = '" + name + "'"
GOOD - Parameterized queries:
python# SAFE cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) # SQLAlchemy session.query(User).filter(User.id == user_id).first() # Prisma await prisma.user.findUnique({ where: { id: userId } })
BAD - Catches everything:
python# VULNERABLE - hides bugs, catches KeyboardInterrupt try: risky_operation() except: pass # VULNERABLE - too broad except Exception: log.error("Something failed")
GOOD - Specific exceptions:
python# SAFE - specific exceptions try: risky_operation() except ValueError as e: log.warning(f"Invalid value: {e}") except ConnectionError as e: log.error(f"Connection failed: {e}") raise
BAD - User input in shell:
python# VULNERABLE os.system(f"grep {user_input} /var/log/app.log") import subprocess subprocess.run(f"ls {directory}", shell=True)
GOOD - Avoid shell, use lists:
python# SAFE - no shell subprocess.run(["grep", user_input, "/var/log/app.log"]) # SAFE - validated input if not re.match(r'^[a-zA-Z0-9_-]+$', directory): raise ValueError("Invalid directory name") subprocess.run(["ls", directory])
BAD - User input in paths:
python# VULNERABLE path = f"/uploads/{user_filename}" with open(path) as f: return f.read()
GOOD - Validate and sanitize:
python# SAFE from pathlib import Path upload_dir = Path("/uploads").resolve() requested = (upload_dir / user_filename).resolve() if not requested.is_relative_to(upload_dir): raise ValueError("Path traversal attempt") with open(requested) as f: return f.read()
BAD - Secrets in code:
python# VULNERABLE API_KEY = "sk-1234567890abcdef" DB_PASSWORD = "super_secret_password"
GOOD - Environment variables:
python# SAFE import os API_KEY = os.environ["API_KEY"] DB_PASSWORD = os.environ["DB_PASSWORD"] # Or with defaults for development API_KEY = os.getenv("API_KEY", "dev-key-only")
BAD - Unsanitized output:
html<!-- VULNERABLE --> <div>{{ user_input }}</div>
GOOD - Proper escaping:
html<!-- SAFE - auto-escaped in most frameworks --> <div>{{ user_input | e }}</div> <!-- Or use textContent in JS --> element.textContent = userInput; // Safe
| Severity | Impact | Examples | |----------|--------|----------| | CRITICAL | Data breach, RCE | SQL injection, shell injection | | HIGH | Data exposure, privilege escalation | Path traversal, hardcoded secrets | | MEDIUM | Information disclosure | Verbose errors, bare excepts | | LOW | Best practice violation | Missing input validation |
pythonVULNERABLE_PATTERNS = { "sql_injection": [ r'execute\([\'"].*%s.*[\'"].*%', # % formatting in SQL r'execute\(f[\'"]', # f-string in SQL r'execute\([\'"].*\+', # String concat in SQL ], "shell_injection": [ r'os\.system\(', # os.system r'subprocess\..*shell=True', # shell=True r'eval\(', # eval r'exec\(', # exec ], "bare_except": [ r'except\s*:', # bare except ], "hardcoded_secrets": [ r'password\s*=\s*[\'"]', # password = "..." r'api_key\s*=\s*[\'"]', # api_key = "..." r'secret\s*=\s*[\'"]', # secret = "..." ], }
typescriptconst VULNERABLE_PATTERNS = { sqlInjection: [ /`SELECT.*\$\{/, // Template literal in SQL /"SELECT.*" \+ /, // String concat in SQL ], xss: [ /innerHTML\s*=/, // innerHTML assignment /dangerouslySetInnerHTML/, // React dangerous prop ], shellInjection: [ /exec\([`'"]/, // child_process.exec /spawn\(.*shell:\s*true/, // shell: true ], };
markdownCheck these high-risk areas first: - Authentication/authorization code - Database queries - File operations - External API calls - User input handling - Serialization/deserialization
markdownFor each source file: Match against vulnerability patterns Record file, line, pattern matched Assess severity
markdown# Security Audit Report ## Summary - CRITICAL: 2 - HIGH: 5 - MEDIUM: 12 ## Critical Issues ### 1. SQL Injection in user_service.py:45 Pattern: f-string in execute()
cursor.execute(f"SELECT FROM users WHERE id = {user_id}")
**Fix**: Use parameterized querycursor.execute("SELECT FROM users WHERE id = %s", (user_id,))
Run security audit in code-related lanes:
markdownLane: SL-API Post-implementation checks: 1. ✓ Tests pass 2. ✓ Lint clean 3. ⚠️ Security audit: 2 MEDIUM issues Review security findings before merge.
yaml- name: Security Audit run: | # Check for vulnerable patterns grep -rn "execute(f" --include="*.py" && exit 1 || true grep -rn "shell=True" --include="*.py" && exit 1 || true grep -rn "except:" --include="*.py" && echo "Warning: bare except found"
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 14,715 | 12,496 | -15% | 1 | 1 | 0% | 1,838 | 3,175 | +73% | 0 | 0 | — |
case-02 | fail→fail | 7,953 | 8,823 | +11% | 1 | 1 | 0% | 902 | 2,849 | +216% | 0 | 0 | — |
case-03 | fail→fail | 9,224 | 11,864 | +29% | 1 | 1 | 0% | 832 | 3,114 | +274% | 0 | 0 | — |
case-04 | pass→pass | 14,286 | 15,669 | +10% | 1 | 1 | 0% | 2,869 | 5,435 | +89% | 0 | 0 | — |
case-05 | pass→pass | 16,513 | 15,483 | -6% | 1 | 1 | 0% | 3,546 | 5,265 | +48% | 0 | 0 | — |
case-06 | pass→pass | 4,666 | 4,904 | +5% | 1 | 1 | 0% | 851 | 2,886 | +239% | 0 | 0 | — |
case-07 | pass→pass | 11,715 | 11,804 | +1% | 1 | 1 | 0% | 2,097 | 2,927 | +40% | 0 | 0 | — |
case-08 | fail→pass | 14,212 | 8,887 | -37% | 1 | 1 | 0% | 2,481 | 3,404 | +37% | 0 | 0 | — |
case-09 | pass→pass | 13,262 | 10,448 | -21% | 1 | 1 | 0% | 2,475 | 3,384 | +37% | 0 | 0 | — |
case-10 | pass→pass | 13,044 | 6,721 | -48% | 1 | 1 | 0% | 2,272 | 3,395 | +49% | 0 | 0 | — |
case-11 | pass→pass | 11,509 | 7,667 | -33% | 1 | 1 | 0% | 2,007 | 3,446 | +72% | 0 | 0 | — |
case-12 | pass→pass | 10,989 | 5,044 | -54% | 1 | 1 | 0% | 1,789 | 2,903 | +62% | 0 | 0 | — |
case-13 | pass→pass | 14,061 | 9,136 | -35% | 1 | 1 | 0% | 2,254 | 2,955 | +31% | 0 | 0 | — |
case-14 | pass→pass | 8,767 | 7,195 | -18% | 1 | 1 | 0% | 1,744 | 3,479 | +99% | 0 | 0 | — |
case-15 | fail→pass | 7,662 | 3,619 | -53% | 1 | 1 | 0% | 1,121 | 2,327 | +108% | 0 | 0 | — |
case-16 | fail→pass | 8,784 | 1,142 | -87% | 1 | 1 | 0% | 1,189 | 2,286 | +92% | 0 | 0 | — |
case-17 | fail→pass | 14,438 | 6,726 | -53% | 1 | 1 | 0% | 2,090 | 3,113 | +49% | 0 | 0 | — |
case-18 | pass→pass | 11,834 | 4,517 | -62% | 1 | 1 | 0% | 1,795 | 2,895 | +61% | 0 | 0 | — |
case-19 | pass→pass | 12,126 | 4,262 | -65% | 1 | 1 | 0% | 1,836 | 2,661 | +45% | 0 | 0 | — |
case-20 | fail→pass | 9,927 | 4,698 | -53% | 1 | 1 | 0% | 1,583 | 2,865 | +81% | 0 | 0 | — |
case-21 | pass→pass | 13,558 | 5,274 | -61% | 1 | 1 | 0% | 2,354 | 2,978 | +27% | 0 | 0 | — |
case-22 | pass→pass | 12,726 | 4,369 | -66% | 1 | 1 | 0% | 2,313 | 2,849 | +23% | 0 | 0 | — |
case-23 | pass→pass | 8,467 | 3,332 | -61% | 1 | 1 | 0% | 1,398 | 2,409 | +72% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +22 percentage points is the difference between those two pass rates over the 23 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.