
Security Scan
- 379 installs
- 133 repo stars
- Updated February 24, 2026
- jwynia/agent-skills
security-scan is an agent skill that runs structured security scans on codebases or infrastructure configs before release to surface vulnerabilities, misconfigurations, and compliance gaps for developer remediation.
About
security-scan is a skill from jwynia/agent-skills that orchestrates structured security scanning across application code and configuration files before release. The agent follows a defined scan workflow to identify dependency CVEs, insecure defaults, exposed secrets patterns, and compliance gaps rather than ad-hoc grep searches. Developers invoke security-scan when preparing a release candidate, onboarding a inherited repo, or responding to audit requests. Output is organized findings with severity and remediation guidance suitable for ticket creation. The skill complements manual code review by systematically covering common OWASP and misconfiguration categories across the repository tree.
- Vuln detection
- Config review
- Pre-release checks
- Risk triage
- Compliance hints
Security Scan by the numbers
- 379 all-time installs (skills.sh)
- +2 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #565 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/jwynia/agent-skills --skill security-scanAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 379 |
|---|---|
| repo stars | ★ 133 |
| Last updated | February 24, 2026 |
| Repository | jwynia/agent-skills ↗ |
How do you scan a codebase before release?
Run structured security scans on codebases or configs before release to surface vulnerabilities, misconfigurations, and compliance gaps for remediation.
Who is it for?
Developers preparing a release or audit who need a systematic security pass over code and configs beyond spot-checking individual files.
Skip if: Skip security-scan when you need certified penetration testing, runtime DAST against production URLs, or SOC2 auditor sign-off.
When should I use this skill?
User asks for a security scan, vulnerability review, or pre-release security audit of the repository or deployment configs.
What you get
Prioritized vulnerability report, misconfiguration list, compliance gap notes, and remediation recommendations.
Files
Security Scan
Comprehensive security vulnerability detection for codebases.
Quick Start
/security-scan # Full scan of current directory
/security-scan --scope src/ # Scan specific directory
/security-scan --quick # Fast scan (critical issues only)
/security-scan --focus injection # Focus on specific categoryWhat This Skill Does
Analyzes code for security vulnerabilities across multiple categories:
1. OWASP Top 10 - Industry-standard web vulnerability categories 2. Secrets Detection - Hardcoded credentials, API keys, tokens 3. Injection Flaws - SQL, XSS, command injection patterns 4. Cryptographic Issues - Weak algorithms, insecure implementations 5. Configuration Problems - Insecure defaults, misconfigurations
Scan Modes
Full Scan (Default)
Comprehensive analysis of all security categories.
/security-scanChecks performed:
- All OWASP Top 10 categories
- Secrets and credential detection
- Dependency vulnerabilities (if package files exist)
- Configuration file review
Duration: 2-5 minutes depending on codebase size
Quick Scan
Fast check for critical and high-severity issues only.
/security-scan --quickChecks performed:
- Critical injection patterns
- Exposed secrets
- Known dangerous functions
Duration: Under 1 minute
Focused Scan
Target specific vulnerability category.
/security-scan --focus <category>Categories:
injection- SQL, XSS, command injectionsecrets- Credentials, API keys, tokenscrypto- Cryptographic weaknessesauth- Authentication/authorization issuesconfig- Configuration security
Output Format
Severity Levels
| Level | Icon | Meaning | Action Required |
|---|---|---|---|
| CRITICAL | [!] | Exploitable vulnerability | Immediate fix |
| HIGH | [H] | Serious security risk | Fix before deploy |
| MEDIUM | [M] | Potential vulnerability | Plan to address |
| LOW | [L] | Minor issue or hardening | Consider fixing |
| INFO | [i] | Informational finding | Awareness only |
Finding Format
[SEVERITY] CATEGORY: Brief description
File: path/to/file.ext:line
Pattern: What was detected
Risk: Why this is dangerous
Fix: How to remediateSummary Report
SECURITY SCAN RESULTS
=====================
Scope: src/
Files scanned: 127
Duration: 45 seconds
FINDINGS BY SEVERITY
Critical: 2
High: 5
Medium: 12
Low: 8
TOP ISSUES
1. [!] SQL Injection in src/api/users.ts:45
2. [!] Hardcoded AWS key in src/config.ts:12
3. [H] XSS vulnerability in src/components/Comment.tsx:89
...
Run `/security-scan --details` for full report.OWASP Top 10 Coverage
| # | Category | Detection Approach |
|---|---|---|
| A01 | Broken Access Control | Authorization pattern analysis |
| A02 | Cryptographic Failures | Weak crypto detection |
| A03 | Injection | Pattern matching + data flow |
| A04 | Insecure Design | Security control gaps |
| A05 | Security Misconfiguration | Config file analysis |
| A06 | Vulnerable Components | Dependency scanning |
| A07 | Auth Failures | Auth pattern review |
| A08 | Data Integrity Failures | Deserialization checks |
| A09 | Logging Failures | Audit log analysis |
| A10 | SSRF | Request pattern detection |
See references/owasp/ for detailed detection rules per category.
Detection Patterns
Injection Detection
SQL Injection:
- String concatenation in queries
- Unsanitized user input in database calls
- Dynamic query constructionCross-Site Scripting (XSS):
- innerHTML assignments with user data
- document.write() with dynamic content
- Unescaped template interpolationCommand Injection:
- exec(), system(), popen() with user input
- Shell command string construction
- Unsanitized subprocess argumentsSee references/patterns/ for language-specific patterns.
Secrets Detection
High-Confidence Patterns:
AWS Access Key: AKIA[0-9A-Z]{16}
AWS Secret Key: [A-Za-z0-9/+=]{40}
GitHub Token: gh[pousr]_[A-Za-z0-9]{36,}
Stripe Key: sk_live_[A-Za-z0-9]{24,}
Private Key: -----BEGIN (RSA |EC )?PRIVATE KEY-----Medium-Confidence Patterns:
Generic API Key: api[_-]?key.*[=:]\s*['"][a-zA-Z0-9]{16,}
Password in Code: password\s*[=:]\s*['"][^'"]+['"]
Connection String: (mysql|postgres|mongodb)://[^:]+:[^@]+@Cryptographic Weaknesses
Weak Algorithms:
- MD5 for password hashing
- SHA1 for security purposes
- DES/3DES encryption
- RC4 stream cipherImplementation Issues:
- Hardcoded encryption keys
- Weak random number generation
- Missing salt in password hashing
- ECB mode encryptionIntegration with Other Skills
With /secrets-scan
Focused deep-dive on credential detection:
/secrets-scan # Dedicated secrets analysis
/secrets-scan --entropy # High-entropy string detectionWith /dependency-scan
Package vulnerability analysis:
/dependency-scan # Check all dependencies
/dependency-scan --fix # Auto-fix where possibleWith /config-scan
Infrastructure and configuration review:
/config-scan # All config files
/config-scan --docker # Container security
/config-scan --iac # Infrastructure as CodeScan Execution Protocol
Phase 1: Discovery
1. Identify project type (languages, frameworks)
2. Locate relevant files (source, config, dependencies)
3. Determine applicable security rulesPhase 2: Static Analysis
1. Pattern matching for known vulnerabilities
2. Data flow analysis for injection paths
3. Configuration reviewPhase 3: Secrets Scanning
1. High-confidence pattern matching
2. Entropy analysis for potential secrets
3. Git history check (optional)Phase 4: Dependency Analysis
1. Parse package manifests
2. Check against vulnerability databases
3. Identify outdated packagesPhase 5: Reporting
1. Deduplicate findings
2. Assign severity scores
3. Generate actionable report
4. Provide remediation guidanceConfiguration
Project-Level Config
Create .security-scan.yaml in project root:
# Scan configuration
scan:
exclude:
- "node_modules/**"
- "vendor/**"
- "**/*.test.ts"
- "**/__mocks__/**"
# Severity thresholds
thresholds:
fail_on: critical # critical, high, medium, low
warn_on: medium
# Category toggles
categories:
injection: true
secrets: true
crypto: true
auth: true
config: true
dependencies: true
# Custom patterns
patterns:
secrets:
- name: "Internal API Key"
pattern: "INTERNAL_[A-Z]{3}_KEY_[a-zA-Z0-9]{32}"
severity: highIgnore Patterns
Create .security-scan-ignore for false positives:
# Ignore specific files
src/test/fixtures/mock-credentials.ts
# Ignore specific lines (use inline comment)
# security-scan-ignore: test fixture
const mockApiKey = "sk_test_fake123";Command Reference
| Command | Description |
|---|---|
/security-scan | Full security scan |
/security-scan --quick | Critical issues only |
/security-scan --scope <path> | Scan specific path |
/security-scan --focus <cat> | Single category |
/security-scan --details | Verbose output |
/security-scan --json | JSON output |
/security-scan --fix | Auto-fix where possible |
Related Skills
/secrets-scan- Deep secrets detection/dependency-scan- Package vulnerability analysis/config-scan- Configuration security review/review-code- General code review (includes security)
References
references/owasp/- OWASP Top 10 detection detailsreferences/patterns/- Language-specific vulnerability patternsreferences/remediation/- Fix guidance by vulnerability typeassets/severity-matrix.md- Severity scoring criteria
Security Severity Matrix
Criteria for classifying vulnerability severity.
Severity Levels
| Level | Score | Impact | Exploitability | Action |
|---|---|---|---|---|
| CRITICAL | 9.0-10.0 | System compromise | Easy, no auth | Immediate |
| HIGH | 7.0-8.9 | Data breach possible | Moderate | Before deploy |
| MEDIUM | 4.0-6.9 | Limited impact | Requires effort | Plan to fix |
| LOW | 0.1-3.9 | Minimal risk | Difficult | Consider |
| INFO | 0.0 | No direct risk | N/A | Awareness |
Classification by Category
Injection
| Finding | Severity |
|---|---|
| SQL injection with auth bypass | CRITICAL |
| SQL injection (data access) | HIGH |
| NoSQL injection (MongoDB) | HIGH |
| Stored XSS | CRITICAL |
| Reflected XSS | HIGH |
| DOM-based XSS | MEDIUM |
| Command injection | CRITICAL |
| LDAP injection | HIGH |
| Template injection (SSTI) | CRITICAL |
Cryptography
| Finding | Severity |
|---|---|
| Hardcoded encryption keys | CRITICAL |
| MD5/SHA1 for passwords | CRITICAL |
| Weak encryption (DES/RC4) | HIGH |
| ECB mode encryption | HIGH |
| Math.random() for tokens | HIGH |
| Missing password salt | HIGH |
| Disabled TLS verification | CRITICAL |
| Weak TLS version (1.0/1.1) | MEDIUM |
Secrets
| Finding | Severity |
|---|---|
| AWS credentials in code | CRITICAL |
| Private keys committed | CRITICAL |
| API keys in source | HIGH |
| Database passwords in code | HIGH |
| JWT secrets hardcoded | HIGH |
| Test credentials in prod | MEDIUM |
| Generic secrets in config | MEDIUM |
Access Control
| Finding | Severity |
|---|---|
| Admin endpoint without auth | CRITICAL |
| IDOR on sensitive data | CRITICAL |
| Missing authorization | HIGH |
| CORS allows all origins | HIGH |
| Path traversal (system files) | CRITICAL |
| Path traversal (user files) | HIGH |
| Privilege escalation possible | CRITICAL |
| Mass assignment | MEDIUM |
Configuration
| Finding | Severity |
|---|---|
| Debug mode in production | HIGH |
| Verbose error messages | MEDIUM |
| Default credentials | CRITICAL |
| Missing security headers | MEDIUM |
| Exposed admin interfaces | HIGH |
| Directory listing enabled | LOW |
| Insecure cookie flags | MEDIUM |
Dependencies
| Finding | Severity |
|---|---|
| Known RCE vulnerability | CRITICAL |
| Known auth bypass CVE | CRITICAL |
| Known XSS CVE | HIGH |
| Known DoS vulnerability | MEDIUM |
| Outdated (no known CVE) | LOW |
| Deprecated package | INFO |
SSRF
| Finding | Severity |
|---|---|
| SSRF to internal network | CRITICAL |
| SSRF to cloud metadata | CRITICAL |
| SSRF with protocol control | HIGH |
| Open redirect | MEDIUM |
Deserialization
| Finding | Severity |
|---|---|
| pickle.loads with user data | CRITICAL |
| Unsafe YAML loading | HIGH |
| Java deserialization | CRITICAL |
| PHP unserialize | HIGH |
Scoring Factors
Impact Score (0-10)
| Factor | Weight |
|---|---|
| Confidentiality | 0-3.3 |
| Integrity | 0-3.3 |
| Availability | 0-3.3 |
Exploitability Score (0-10)
| Factor | Weight |
|---|---|
| Attack complexity | 0-2.5 |
| Privileges required | 0-2.5 |
| User interaction | 0-2.5 |
| Attack vector | 0-2.5 |
Final Score
Severity = (Impact * 0.6) + (Exploitability * 0.4)Adjustment Factors
Increase Severity When:
- Public-facing application (+1 level)
- Handles financial data (+1 level)
- Handles health data (+1 level)
- No compensating controls (+1 level)
- Easily automatable exploit (+0.5 level)
Decrease Severity When:
- Internal-only application (-0.5 level)
- Defense in depth present (-0.5 level)
- Limited data scope (-0.5 level)
- Requires physical access (-1 level)
Response Timeframes
| Severity | Maximum Fix Time | Escalation |
|---|---|---|
| CRITICAL | 24 hours | Immediate to leadership |
| HIGH | 7 days | Security team |
| MEDIUM | 30 days | Sprint planning |
| LOW | 90 days | Backlog |
| INFO | Optional | None |
Report Format
[SEVERITY] CATEGORY: Title
File: path/to/file.ext:line
Pattern: Matched code pattern
CWE: CWE-XXX
CVSS: X.X
Risk: What could happen if exploited
Evidence: Specific code/config found
Remediation: How to fix
References:
- OWASP link
- CWE linkA01: Broken Access Control
Detection rules for OWASP A01 - Broken Access Control.
Overview
Access control enforces policy so users cannot act outside their intended permissions. Failures typically lead to unauthorized information disclosure, modification, or destruction of data.
Detection Patterns
Missing Authorization Checks
Pattern: Endpoints or functions without authorization verification.
// VULNERABLE: No auth check
app.get('/api/admin/users', async (req, res) => {
const users = await User.findAll();
res.json(users);
});
// SECURE: Authorization required
app.get('/api/admin/users', requireAuth, requireRole('admin'), async (req, res) => {
const users = await User.findAll();
res.json(users);
});Regex patterns:
# Express routes without middleware
app\.(get|post|put|delete|patch)\s*\(\s*['"][^'"]*admin[^'"]*['"]\s*,\s*async?\s*\(
# Django views without decorators
def\s+\w+\(request[^)]*\):\s*\n\s+[^@]
# Missing @authorize in .NET
\[Http(Get|Post|Put|Delete)\]\s*\n\s*publicInsecure Direct Object Reference (IDOR)
Pattern: User-controlled IDs used without ownership verification.
// VULNERABLE: No ownership check
app.get('/api/orders/:id', async (req, res) => {
const order = await Order.findById(req.params.id);
res.json(order);
});
// SECURE: Verify ownership
app.get('/api/orders/:id', async (req, res) => {
const order = await Order.findOne({
_id: req.params.id,
userId: req.user.id // Ownership check
});
if (!order) return res.status(404).json({ error: 'Not found' });
res.json(order);
});Regex patterns:
# Direct ID usage without user context
findById\s*\(\s*req\.(params|query|body)\.\w+\s*\)
Model\.find\s*\(\s*\{\s*_id:\s*req\.
# Path traversal in file access
path\.join\s*\([^)]*req\.(params|query|body)Path Traversal
Pattern: User input used in file paths without sanitization.
# VULNERABLE
def download_file(request):
filename = request.GET['file']
filepath = os.path.join('/uploads/', filename)
return FileResponse(open(filepath, 'rb'))
# SECURE
def download_file(request):
filename = os.path.basename(request.GET['file']) # Strip path
filepath = os.path.join('/uploads/', filename)
# Verify within allowed directory
if not os.path.realpath(filepath).startswith('/uploads/'):
raise PermissionError("Invalid path")
return FileResponse(open(filepath, 'rb'))Regex patterns:
# Python file operations with user input
open\s*\(\s*.*request\.(GET|POST|args|form)
os\.path\.join\s*\([^)]*request\.
# Node.js file operations
fs\.(readFile|writeFile|unlink)\s*\([^)]*req\.(params|query|body)
path\.join\s*\([^)]*req\.Privilege Escalation
Pattern: Role changes or privilege modifications without proper verification.
// VULNERABLE: User can set their own role
app.put('/api/user/profile', async (req, res) => {
await User.update(req.user.id, req.body); // Could include role!
});
// SECURE: Whitelist allowed fields
app.put('/api/user/profile', async (req, res) => {
const { name, email } = req.body; // Only allow safe fields
await User.update(req.user.id, { name, email });
});Regex patterns:
# Mass assignment risks
\.update\s*\([^)]*req\.body\s*\)
Object\.assign\s*\([^)]*req\.body
\.\.\.\s*req\.bodyCORS Misconfiguration
Pattern: Overly permissive CORS settings.
// VULNERABLE: Allow all origins
app.use(cors({ origin: '*' }));
app.use(cors({ origin: true }));
// VULNERABLE: Reflect origin
app.use(cors({ origin: req.headers.origin }));
// SECURE: Whitelist origins
app.use(cors({
origin: ['https://app.example.com', 'https://admin.example.com']
}));Regex patterns:
Access-Control-Allow-Origin:\s*\*
cors\s*\(\s*\{\s*origin:\s*['"]\*['"]
cors\s*\(\s*\{\s*origin:\s*trueSeverity Classification
| Finding | Severity |
|---|---|
| Admin endpoint without auth | CRITICAL |
| IDOR in sensitive data | CRITICAL |
| Path traversal to system files | CRITICAL |
| Missing auth on data modification | HIGH |
| CORS allows all origins | HIGH |
| IDOR in non-sensitive data | MEDIUM |
| Missing rate limiting on auth | MEDIUM |
| Verbose access denied errors | LOW |
Remediation Guidance
Authorization Middleware
Implement consistent authorization at the framework level:
// Middleware that runs on all routes
const authMiddleware = (requiredRole) => (req, res, next) => {
if (!req.user) return res.status(401).json({ error: 'Unauthorized' });
if (requiredRole && req.user.role !== requiredRole) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};Ownership Verification
Always verify resource ownership:
const verifyOwnership = async (resourceType, resourceId, userId) => {
const resource = await resourceType.findById(resourceId);
if (!resource || resource.userId !== userId) {
throw new ForbiddenError('Access denied');
}
return resource;
};Path Sanitization
Never trust user input in file paths:
const safePath = (basePath, userInput) => {
const filename = path.basename(userInput); // Strip directory
const fullPath = path.resolve(basePath, filename);
// Verify still within base path
if (!fullPath.startsWith(path.resolve(basePath))) {
throw new Error('Invalid path');
}
return fullPath;
};References
A02: Cryptographic Failures
Detection rules for OWASP A02 - Cryptographic Failures.
Overview
Failures related to cryptography which often lead to exposure of sensitive data. This includes weak algorithms, poor key management, and insecure data transmission.
Detection Patterns
Weak Hashing Algorithms
Pattern: Using MD5, SHA1 for passwords or security purposes.
# VULNERABLE
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest()
password_hash = hashlib.sha1(password.encode()).hexdigest()
# SECURE
import bcrypt
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())Regex patterns:
# Python
hashlib\.md5\s*\(
hashlib\.sha1\s*\(
MD5\.new\s*\(
# JavaScript
crypto\.createHash\s*\(\s*['"]md5['"]
crypto\.createHash\s*\(\s*['"]sha1['"]
md5\s*\(
# Java
MessageDigest\.getInstance\s*\(\s*["']MD5["']
MessageDigest\.getInstance\s*\(\s*["']SHA-?1["']
# PHP
md5\s*\(
sha1\s*\(Weak Encryption Algorithms
Pattern: Using DES, 3DES, RC4, or ECB mode.
// VULNERABLE
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
// SECURE
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");Regex patterns:
# DES/3DES
DES|DESede|TripleDES
Cipher\.getInstance\s*\(\s*["'][^"']*DES
# ECB Mode (any algorithm)
/ECB/
Cipher\.getInstance\s*\(\s*["'][^"']*/ECB/
# RC4
RC4|ARCFOURHardcoded Cryptographic Keys
Pattern: Encryption keys embedded in source code.
// VULNERABLE
const encryptionKey = "MySecretKey12345";
const AES_KEY = Buffer.from('0123456789abcdef');
// SECURE
const encryptionKey = process.env.ENCRYPTION_KEY;Regex patterns:
# Key variable assignments
(encryption|aes|secret|crypto)[-_]?key\s*[=:]\s*['"][^'"]+['"]
# Direct key in crypto calls
\.encrypt\s*\([^)]*['"][A-Za-z0-9+/=]{16,}['"]
createCipheriv\s*\([^)]*['"][A-Za-z0-9+/=]{16,}['"]Weak Random Number Generation
Pattern: Using non-cryptographic random for security purposes.
// VULNERABLE
const token = Math.random().toString(36);
const sessionId = Math.floor(Math.random() * 1000000);
// SECURE
const crypto = require('crypto');
const token = crypto.randomBytes(32).toString('hex');Regex patterns:
# JavaScript
Math\.random\s*\(\s*\)
# Python
random\.(random|randint|choice)\s*\(
# Java (not SecureRandom)
new\s+Random\s*\(
java\.util\.Random
# PHP
rand\s*\(
mt_rand\s*\(Missing Password Salt
Pattern: Hashing passwords without unique salt.
# VULNERABLE
password_hash = sha256(password).hexdigest()
# SECURE
salt = os.urandom(32)
password_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)Regex patterns:
# Direct hash without salt parameter
sha256\s*\(\s*password
bcrypt\.hash\s*\([^,]+\s*\)$ # Missing salt parameterInsecure TLS Configuration
Pattern: Disabled certificate verification or weak TLS versions.
# VULNERABLE
requests.get(url, verify=False)
ssl_context.check_hostname = False
urllib3.disable_warnings()
# SECURE
requests.get(url, verify=True)Regex patterns:
# Python
verify\s*=\s*False
check_hostname\s*=\s*False
disable_warnings\s*\(
CERT_NONE
# Node.js
rejectUnauthorized\s*:\s*false
NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*['"]?0
# General
SSLv2|SSLv3|TLSv1\.0|TLSv1\.1Sensitive Data in Logs
Pattern: Logging passwords, tokens, or keys.
# VULNERABLE
logger.info(f"User login: {username}, password: {password}")
console.log("API Key:", apiKey);
# SECURE
logger.info(f"User login: {username}")Regex patterns:
(log|print|console\.(log|info|debug))\s*\([^)]*password
(log|print|console\.(log|info|debug))\s*\([^)]*apiKey
(log|print|console\.(log|info|debug))\s*\([^)]*secret
(log|print|console\.(log|info|debug))\s*\([^)]*tokenSeverity Classification
| Finding | Severity |
|---|---|
| Hardcoded encryption keys | CRITICAL |
| MD5/SHA1 for passwords | CRITICAL |
| Disabled TLS verification | CRITICAL |
| DES/3DES encryption | HIGH |
| ECB mode encryption | HIGH |
| Math.random() for tokens | HIGH |
| Missing password salt | HIGH |
| Sensitive data in logs | HIGH |
| Weak TLS versions | MEDIUM |
| Hardcoded IV values | MEDIUM |
Remediation Guidance
Password Hashing
Use bcrypt, scrypt, or Argon2:
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12;
// Hash password
const hash = await bcrypt.hash(password, SALT_ROUNDS);
// Verify password
const match = await bcrypt.compare(password, hash);Encryption
Use AES-GCM with proper key management:
const crypto = require('crypto');
function encrypt(text, key) {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return { iv: iv.toString('hex'), encrypted, authTag: authTag.toString('hex') };
}Secure Random
Use cryptographic random sources:
const crypto = require('crypto');
// Generate random token
const token = crypto.randomBytes(32).toString('hex');
// Generate random number in range
const randomInt = crypto.randomInt(0, 1000000);References
A03: Injection
Detection rules for OWASP A03 - Injection.
Overview
Injection flaws occur when untrusted data is sent to an interpreter as part of a command or query. This includes SQL, NoSQL, OS command, LDAP, and XPath injection.
Detection Patterns
SQL Injection
Pattern: User input concatenated into SQL queries.
// VULNERABLE
const query = "SELECT * FROM users WHERE id = " + userId;
const query = `SELECT * FROM users WHERE name = '${userName}'`;
db.query("SELECT * FROM users WHERE email = '" + email + "'");
// SECURE
const query = "SELECT * FROM users WHERE id = ?";
db.query(query, [userId]);Regex patterns:
# String concatenation in SQL
SELECT\s+.*\+\s*\$?\w+
SELECT\s+.*\$\{[^}]+\}
['"]SELECT\s+.*['"].*\+
# Template literals with SQL
`SELECT[^`]*\$\{
# ORM raw queries with user input
\.raw\s*\([^)]*\$
\.rawQuery\s*\([^)]*req\.
execute\s*\([^)]*\+Language-specific patterns:
# Python
cursor\.execute\s*\([^)]*%\s*\(
cursor\.execute\s*\([^)]*\.format\s*\(
f["']SELECT[^"']*\{
# PHP
mysql_query\s*\([^)]*\$
mysqli_query\s*\([^)]*\$_
\$wpdb->query\s*\([^)]*\$
# Java
executeQuery\s*\([^)]*\+
createQuery\s*\([^)]*\+\s*\w+
Statement\s*.*execute.*\+NoSQL Injection
Pattern: User input in NoSQL queries without sanitization.
// VULNERABLE
db.users.find({ username: req.body.username }); // Object injection possible
db.users.find({ $where: `this.name == '${name}'` });
// SECURE
const username = String(req.body.username); // Force string type
db.users.find({ username: { $eq: username } });Regex patterns:
# MongoDB object injection
\.find\s*\(\s*\{\s*\w+:\s*req\.(body|query|params)
\.findOne\s*\(\s*req\.body
# $where operator with user input
\$where.*\$\{
\$where.*\+\s*\w+
# Mongoose with raw objects
Model\.find\s*\(req\.body\)Command Injection
Pattern: User input passed to shell commands.
# VULNERABLE
os.system("ping " + ip_address)
subprocess.call("ls " + user_input, shell=True)
exec("echo " + message)
# SECURE
subprocess.run(["ping", "-c", "1", ip_address], shell=False)Regex patterns:
# Python
os\.system\s*\([^)]*\+
os\.popen\s*\([^)]*\+
subprocess\.(call|run|Popen)\s*\([^)]*shell\s*=\s*True
exec\s*\([^)]*\+
eval\s*\([^)]*request
# JavaScript/Node.js
child_process\.exec\s*\([^)]*\+
child_process\.exec\s*\([^)]*\$\{
exec\s*\([^)]*req\.(body|query|params)
spawn\s*\([^)]*\{.*shell:\s*true
# PHP
system\s*\([^)]*\$
exec\s*\([^)]*\$
passthru\s*\([^)]*\$
shell_exec\s*\([^)]*\$
`[^`]*\$[^`]*`
# Ruby
system\s*\([^)]*\#\{
`[^`]*\#\{[^`]*`
exec\s*\([^)]*\+Cross-Site Scripting (XSS)
Pattern: User input rendered in HTML without escaping.
// VULNERABLE
element.innerHTML = userInput;
document.write(userData);
$(element).html(userContent);
res.send("<div>" + userName + "</div>");
// SECURE
element.textContent = userInput;
const escaped = escapeHtml(userInput);
$(element).text(userContent);Regex patterns:
# JavaScript DOM
\.innerHTML\s*=
document\.write\s*\(
\.outerHTML\s*=
# jQuery
\$\([^)]*\)\.html\s*\(
\$\([^)]*\)\.append\s*\([^)]*\+
# React (dangerouslySetInnerHTML)
dangerouslySetInnerHTML
# Server-side rendering
res\.(send|write)\s*\([^)]*\+
render\s*\([^)]*\+\s*req\.
# Template engines without escaping
\{\{\{\s*\w+\s*\}\}\} # Handlebars unescaped
\{!!\s*\$\w+\s*!!\} # Blade unescaped
\|safe\} # Django/Jinja safe filterLDAP Injection
Pattern: User input in LDAP queries.
// VULNERABLE
String filter = "(uid=" + username + ")";
ctx.search("ou=users", filter, controls);
// SECURE
String safeUser = LdapEncoder.filterEncode(username);
String filter = "(uid=" + safeUser + ")";Regex patterns:
# LDAP filter construction
\(uid=.*\+
\(cn=.*\+
ldap_search\s*\([^)]*\$
search\s*\([^)]*\+.*uid=XPath Injection
Pattern: User input in XPath queries.
// VULNERABLE
String xpath = "//users/user[name='" + name + "']";
// SECURE
XPathExpression expr = xpath.compile("//users/user[name=$name]");
expr.setVariable("name", sanitizedName);Regex patterns:
# XPath with concatenation
xpath\.evaluate\s*\([^)]*\+
selectNodes\s*\([^)]*\+
\[@\w+=.*\+
//\w+\[.*\+Expression Language Injection
Pattern: User input in expression language contexts.
// VULNERABLE (Spring EL)
parser.parseExpression(userInput).getValue();
// VULNERABLE (OGNL)
OgnlContext ctx = new OgnlContext();
Ognl.getValue(userInput, ctx, root);Regex patterns:
# Spring EL
parseExpression\s*\([^)]*\+
parseExpression\s*\(.*request
# OGNL
Ognl\.getValue\s*\([^)]*\+
Ognl\.setValue\s*\([^)]*\+
# MVEL
MVEL\.eval\s*\([^)]*\+Severity Classification
| Finding | Severity |
|---|---|
| SQL injection with auth bypass | CRITICAL |
| Command injection | CRITICAL |
| Stored XSS | CRITICAL |
| SQL injection (data access) | HIGH |
| NoSQL injection | HIGH |
| Reflected XSS | HIGH |
| LDAP injection | HIGH |
| Expression language injection | HIGH |
| DOM-based XSS | MEDIUM |
| XPath injection | MEDIUM |
Remediation Guidance
SQL Injection Prevention
Use parameterized queries:
// Node.js with mysql2
const [rows] = await connection.execute(
'SELECT * FROM users WHERE id = ? AND status = ?',
[userId, 'active']
);
// Sequelize ORM
const user = await User.findOne({
where: { id: userId }
});Command Injection Prevention
Avoid shell execution, use arrays:
# Python - use subprocess with list arguments
import subprocess
import shlex
# SECURE: No shell, arguments as list
subprocess.run(['ping', '-c', '1', ip_address], check=True)
# If shell needed, validate strictly
allowed_hosts = {'google.com', 'example.com'}
if hostname in allowed_hosts:
subprocess.run(['ping', '-c', '1', hostname])XSS Prevention
Escape output appropriately:
// React auto-escapes by default
function SafeComponent({ userInput }) {
return <div>{userInput}</div>; // Auto-escaped
}
// Manual escaping when needed
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}References
A04-A10: Additional OWASP Categories
Detection rules for OWASP categories A04 through A10.
---
A04: Insecure Design
Design flaws that cannot be fixed by implementation alone.
Detection Patterns
Missing Rate Limiting:
# Endpoints without rate limiting
@app\.route.*login
app\.(post|put)\s*\([^)]*password
# Look for absence of rate_limit decoratorsMissing CAPTCHA on Sensitive Actions:
# Registration/password reset without verification
def (register|signup|reset_password|forgot_password)Unrestricted File Upload:
// VULNERABLE: No file type validation
multer({ dest: 'uploads/' })
app.post('/upload', upload.single('file'))
// Look for missing file type checksRegex patterns:
# File upload without validation
multer\s*\(\s*\{[^}]*\}\s*\)(?!.*fileFilter)
upload\.single\s*\(.*\)(?!.*mimetype)
move_uploaded_file\s*\([^)]*\)(?!.*getimagesize)Severity: MEDIUM to HIGH
---
A05: Security Misconfiguration
Insecure default configurations and missing security hardening.
Detection Patterns
Debug Mode in Production:
# VULNERABLE
DEBUG = True
app.run(debug=True)Regex patterns:
DEBUG\s*=\s*True
debug\s*:\s*true
app\.run\s*\([^)]*debug\s*=\s*True
NODE_ENV.*developmentDefault Credentials:
password\s*[=:]\s*['"]?(admin|password|123456|root|test)['"]?
username\s*[=:]\s*['"]?admin['"]?Verbose Error Messages:
// VULNERABLE
app.use((err, req, res, next) => {
res.status(500).json({ error: err.stack }); // Exposes stack trace
});Regex patterns:
\.stack
traceback
stacktrace
err\.message.*res\.(send|json)Missing Security Headers:
# Look for absence in config
X-Frame-Options
X-Content-Type-Options
Content-Security-Policy
Strict-Transport-SecuritySeverity: MEDIUM to HIGH
---
A06: Vulnerable and Outdated Components
Using components with known vulnerabilities.
Detection Patterns
Outdated Package Versions: Check package manifests for known vulnerable versions:
# package.json, requirements.txt, pom.xml, etc.
lodash.*['"](4\.[0-9]|[0-3]\.) # Vulnerable lodash
express.*['"]([0-3]\.|4\.[0-9]\.) # Old expressCommands to Run:
npm audit
pip-audit
safety check
bundler-audit checkRegex patterns:
# Known vulnerable package patterns
jquery.*1\.[0-9]\.
bootstrap.*[0-3]\.
angular.*1\.[0-5]
moment.*2\.[0-9]\.Severity: Varies by CVE (LOW to CRITICAL)
---
A07: Identification and Authentication Failures
Weak authentication mechanisms.
Detection Patterns
Weak Password Requirements:
// VULNERABLE
if (password.length >= 4) { ... }
// SECURE
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{12,}$/;Regex patterns:
# Weak password validation
password\.length\s*>=?\s*[1-7][^0-9]
minlength\s*[=:]\s*[1-7][^0-9]Session Issues:
// VULNERABLE: Predictable session ID
const sessionId = Date.now().toString();
// VULNERABLE: Session in URL
res.redirect('/dashboard?sessionId=' + session.id);Regex patterns:
sessionId.*Date\.now
session.*query\.(id|token|session)
session.*url\s*\+Missing Brute Force Protection:
# No lockout after failed attempts
loginAttempts(?!.*lockout)
failedAttempts(?!.*block)Severity: MEDIUM to CRITICAL
---
A08: Software and Data Integrity Failures
Issues with code and data integrity verification.
Detection Patterns
Insecure Deserialization:
# VULNERABLE
pickle.loads(user_data)
yaml.load(data) # Without LoaderRegex patterns:
# Python
pickle\.loads?\s*\(
yaml\.load\s*\([^)]*\)(?!.*Loader)
marshal\.loads?\s*\(
# Java
ObjectInputStream
readObject\s*\(
XStream\s*\(\s*\)
# PHP
unserialize\s*\([^)]*\$
# Node.js
node-serialize
serialize-javascript.*\(.*\)Missing Integrity Checks:
# Downloads without hash verification
wget(?!.*sha256)
curl.*\|\s*shUnsigned Updates:
# Package installation without verification
pip install.*--trusted-host
npm install.*--ignore-scriptsSeverity: HIGH to CRITICAL
---
A09: Security Logging and Monitoring Failures
Insufficient logging for security events.
Detection Patterns
Missing Security Event Logging:
# Authentication without logging
def login.*:(?!.*log)
function authenticate.*{(?!.*logger)Sensitive Data in Logs:
logger\.(info|debug|warn)\s*\([^)]*password
console\.log\s*\([^)]*apiKey
log\.(info|debug)\s*\([^)]*creditLog Injection:
# VULNERABLE
logger.info(f"User login: {request.GET['username']}")Regex patterns:
# Unsanitized user input in logs
logger\.\w+\s*\([^)]*request\.(GET|POST|body|query)
console\.(log|info)\s*\([^)]*req\.(body|params|query)Severity: LOW to MEDIUM
---
A10: Server-Side Request Forgery (SSRF)
User-supplied URLs used in server-side requests.
Detection Patterns
Direct URL Fetching:
# VULNERABLE
url = request.GET['url']
response = requests.get(url)
# VULNERABLE: PDF generation from URL
pdfkit.from_url(request.POST['url'], 'output.pdf')Regex patterns:
# Python
requests\.(get|post)\s*\(\s*request\.(GET|POST|args|form)
urllib\.request\.urlopen\s*\([^)]*request
httpx\.(get|post)\s*\([^)]*request
# JavaScript
fetch\s*\(\s*req\.(body|query|params)
axios\.(get|post)\s*\([^)]*req\.
http\.request\s*\([^)]*req\.
# General URL parameter usage
(url|uri|link|href)\s*[=:]\s*req\.(body|query|params)Unsafe Redirects:
// VULNERABLE
res.redirect(req.query.returnUrl);Regex patterns:
redirect\s*\(\s*req\.(query|body|params)
Location\s*[=:]\s*req\.SSRF Bypass Patterns to Detect
# Internal network access attempts
127\.0\.0\.1|localhost|0\.0\.0\.0
169\.254\.\d+\.\d+ # AWS metadata
10\.\d+\.\d+\.\d+|172\.(1[6-9]|2[0-9]|3[01])\.
192\.168\.\d+\.\d+Severity: HIGH to CRITICAL
---
Quick Reference: All Categories
| Category | Key Detection Focus | Priority Patterns |
|---|---|---|
| A04 | Rate limiting, file upload | Missing validation |
| A05 | Debug mode, headers | DEBUG=True, verbose errors |
| A06 | Package versions | npm audit, known CVEs |
| A07 | Password policy, sessions | Weak length checks |
| A08 | Deserialization | pickle.loads, unserialize |
| A09 | Log content, coverage | Passwords in logs |
| A10 | URL handling | requests.get(user_url) |
References
JavaScript/TypeScript Security Patterns
Language-specific vulnerability detection patterns.
Injection Vulnerabilities
SQL Injection
# String concatenation in queries
['"`]SELECT\s+.*['"`]\s*\+
['"`]INSERT\s+INTO\s+.*['"`]\s*\+
['"`]UPDATE\s+.*SET\s+.*['"`]\s*\+
['"`]DELETE\s+FROM\s+.*['"`]\s*\+
# Template literals
`SELECT\s+[^`]*\$\{
`INSERT\s+[^`]*\$\{
`UPDATE\s+[^`]*\$\{
# Raw query methods
\.query\s*\([^)]*\$\{
\.query\s*\([^)]*\+
\.raw\s*\([^)]*\$\{
sequelize\.query\s*\([^)]*\$\{
knex\.raw\s*\([^)]*\$\{Command Injection
# child_process
child_process\.exec\s*\([^)]*\$\{
child_process\.exec\s*\([^)]*\+
child_process\.execSync\s*\([^)]*\$\{
require\s*\(\s*['"]child_process['"]\s*\)\.exec\s*\([^)]*\+
# shell option in spawn
spawn\s*\([^)]*\{[^}]*shell\s*:\s*true
# eval with dynamic input
eval\s*\(\s*[^'"][^)]*\)
new\s+Function\s*\([^)]*\+XSS
# DOM manipulation
\.innerHTML\s*=
\.outerHTML\s*=
document\.write\s*\(
document\.writeln\s*\(
# jQuery
\$\s*\([^)]*\)\.html\s*\(
\$\s*\([^)]*\)\.append\s*\([^)]*\$\{
\$\s*\([^)]*\)\.prepend\s*\([^)]*\+
# React dangerous
dangerouslySetInnerHTML
__html\s*:
# Response without encoding
res\.send\s*\([^)]*\+\s*req\.
res\.write\s*\([^)]*\+\s*req\.NoSQL Injection
# MongoDB with user objects
\.find\s*\(\s*req\.body\s*\)
\.findOne\s*\(\s*req\.body\s*\)
\.updateOne\s*\([^)]*req\.body
\.deleteOne\s*\([^)]*req\.body
# $where operator
\$where\s*:.*\$\{
\$where\s*:.*\+
# Mongoose
Model\.\w+\s*\(req\.body\)Cryptographic Issues
Weak Hashing
crypto\.createHash\s*\(\s*['"]md5['"]
crypto\.createHash\s*\(\s*['"]sha1['"]
\.update\s*\(.*\)\.digest\s*\(\s*\) # No algorithm specified
md5\s*\(
sha1\s*\(Weak Random
Math\.random\s*\(\s*\)
# When used for security purposes like tokens, IDsHardcoded Secrets
# API keys
(api[_-]?key|apikey)\s*[=:]\s*['"][a-zA-Z0-9]{16,}['"]
(secret[_-]?key|secretkey)\s*[=:]\s*['"][a-zA-Z0-9]{16,}['"]
# JWT secrets
(jwt[_-]?secret|JWT_SECRET)\s*[=:]\s*['"][^'"]+['"]
# Database credentials
(db[_-]?password|DB_PASSWORD)\s*[=:]\s*['"][^'"]+['"]
# Encryption keys
(encryption[_-]?key|ENCRYPTION_KEY)\s*[=:]\s*['"][^'"]+['"]Insecure TLS
rejectUnauthorized\s*:\s*false
NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*['"]?0
process\.env\.NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*['"]?0Authentication Issues
Session Problems
# Predictable session
sessionId\s*=\s*Date\.now
sessionId\s*=\s*Math\.random
# Session in URL
redirect\s*\([^)]*session[^)]*\)
href\s*=.*\?.*session=
# No httpOnly
cookie\s*[=:]\s*\{[^}]*\}(?!.*httpOnly)Weak Password Policy
password\.length\s*>=?\s*[1-7]\b
minLength\s*:\s*[1-7]\b
\.{4,}\s*$ # Regex allowing very short passwordsAccess Control
Missing Authorization
# Express routes without middleware
app\.(get|post|put|delete|patch)\s*\(\s*['"][^'"]*(?:admin|user|api)[^'"]*['"]\s*,\s*(?:async\s*)?\(req
# Direct ID access
findById\s*\(\s*req\.params\.\w+\s*\)
findById\s*\(\s*req\.query\.\w+\s*\)CORS Issues
Access-Control-Allow-Origin\s*[=:]\s*['"]\*['"]
cors\s*\(\s*\{\s*origin\s*:\s*['"]\*['"]
cors\s*\(\s*\{\s*origin\s*:\s*true
cors\s*\(\s*\) # Default allows allPath Traversal
# File operations with user input
fs\.readFile\s*\([^)]*req\.(params|query|body)
fs\.readFileSync\s*\([^)]*req\.
fs\.writeFile\s*\([^)]*req\.
fs\.unlink\s*\([^)]*req\.
# Path join without validation
path\.join\s*\([^)]*req\.(params|query|body)
path\.resolve\s*\([^)]*req\.SSRF
# HTTP requests with user URLs
fetch\s*\(\s*req\.(body|query|params)
axios\.(get|post|put|delete)\s*\([^)]*req\.
http\.request\s*\([^)]*req\.
https\.request\s*\([^)]*req\.
got\s*\([^)]*req\.Prototype Pollution
# Dangerous merge/extend operations
Object\.assign\s*\(\s*\{\}\s*,\s*.*req\.body
_\.merge\s*\([^)]*req\.body
_\.defaultsDeep\s*\([^)]*req\.body
\.\.\.\s*req\.body # Spread operator
JSON\.parse\s*\(.*req\.(body|query)Denial of Service
ReDoS
# Regex with nested quantifiers
new\s+RegExp\s*\([^)]*(\+|\*)\s*[^)]*(\+|\*)\s*\)
/[^/]*(\+|\*)[^/]*(\+|\*)[^/]*/Resource Exhaustion
# Unbounded loops with user input
for\s*\([^)]*req\.(body|query|params)
while\s*\([^)]*req\.
\.forEach\s*\([^)]*JSON\.parse\s*\(.*req\.Secure Patterns (False Positive Filtering)
These patterns indicate secure usage:
# Parameterized queries
\.query\s*\([^)]*\?\s*,\s*\[
prepared\s*statement
\.escape\s*\(
# Secure random
crypto\.randomBytes
crypto\.randomUUID
uuid\.v4\s*\(
# Input validation
validator\.
\.sanitize\(
escape\s*\(
encodeURIComponent\s*\(Framework-Specific
Express
# Missing helmet
(?!.*helmet)app\.use
# Missing CSRF
(?!.*csrf)app\.(post|put|patch|delete)React
# Dangerous patterns
dangerouslySetInnerHTML
__html\s*:\s*(?!sanitize)Next.js
# API routes without auth
export\s+(default\s+)?async?\s+function\s+(GET|POST|PUT|DELETE|PATCH)(?!.*auth)Python Security Patterns
Language-specific vulnerability detection patterns.
Injection Vulnerabilities
SQL Injection
# String formatting in queries
cursor\.execute\s*\([^)]*%\s*\(
cursor\.execute\s*\([^)]*%\s*[a-zA-Z_]
cursor\.execute\s*\([^)]*\.format\s*\(
cursor\.execute\s*\(f['"]
cursor\.executemany\s*\([^)]*%
# ORM raw queries
\.raw\s*\([^)]*%
\.raw\s*\(f['"]
\.extra\s*\([^)]*%
RawSQL\s*\([^)]*%
# Django
objects\.raw\s*\([^)]*%
objects\.raw\s*\(f['"]
connection\.cursor\s*\(\s*\)\.execute\s*\([^)]*%Command Injection
# os module
os\.system\s*\([^)]*\+
os\.system\s*\(f['"]
os\.popen\s*\([^)]*\+
os\.popen\s*\(f['"]
# subprocess with shell
subprocess\.(call|run|Popen)\s*\([^)]*shell\s*=\s*True
subprocess\.(call|run|Popen)\s*\([^)]*\+[^)]*shell\s*=\s*True
# eval/exec
eval\s*\([^)]*request\.
exec\s*\([^)]*request\.
compile\s*\([^)]*request\.
# Python 2
commands\.getoutput\s*\(
commands\.getstatusoutput\s*\(Template Injection
# Jinja2 unsafe
render_template_string\s*\([^)]*\+
render_template_string\s*\(f['"]
Template\s*\([^)]*\+
Markup\s*\([^)]*\+
# Django templates
Template\s*\([^)]*request\.
mark_safe\s*\([^)]*request\.Cryptographic Issues
Weak Hashing
hashlib\.md5\s*\(
hashlib\.sha1\s*\(
hashlib\.new\s*\(\s*['"]md5['"]
hashlib\.new\s*\(\s*['"]sha1['"]
# PyCrypto
MD5\.new\s*\(
SHA\.new\s*\(
# Without salt for passwords
hashlib\.\w+\s*\([^)]*passwordWeak Random
random\.random\s*\(
random\.randint\s*\(
random\.choice\s*\(
random\.randrange\s*\(
# When used for security (tokens, IDs, passwords)Hardcoded Secrets
# Secret keys
(SECRET_KEY|secret_key)\s*=\s*['"][^'"]+['"]
(API_KEY|api_key)\s*=\s*['"][a-zA-Z0-9]{16,}['"]
# Passwords
(PASSWORD|password|passwd)\s*=\s*['"][^'"]+['"]
# Database URIs with credentials
(DATABASE_URL|database_url)\s*=\s*['"][^'"]*:[^@]*@Insecure TLS
verify\s*=\s*False
ssl\._create_unverified_context
ssl\.CERT_NONE
urllib3\.disable_warnings\s*\(
requests\.(get|post|put|delete)\s*\([^)]*verify\s*=\s*FalseDeserialization
# Pickle (dangerous with untrusted data)
pickle\.loads?\s*\(
cPickle\.loads?\s*\(
_pickle\.loads?\s*\(
shelve\.open\s*\(
# YAML without safe loader
yaml\.load\s*\([^)]*\)(?!.*Loader)
yaml\.load\s*\([^)]*Loader\s*=\s*yaml\.Loader
yaml\.unsafe_load\s*\(
# Marshal
marshal\.loads?\s*\(
# Dill
dill\.loads?\s*\(Path Traversal
# File operations with user input
open\s*\([^)]*request\.(GET|POST|args|form|data)
open\s*\(f['"][^'"]*\{.*request
os\.path\.join\s*\([^)]*request\.
shutil\.(copy|move|rmtree)\s*\([^)]*request\.
# Django
FileResponse\s*\([^)]*request\.
sendfile\s*\([^)]*request\.SSRF
# Requests library
requests\.(get|post|put|delete|head|patch)\s*\([^)]*request\.(GET|POST|args|form)
requests\.(get|post|put|delete|head|patch)\s*\(f['"]
# urllib
urllib\.request\.urlopen\s*\([^)]*request\.
urllib\.request\.urlretrieve\s*\([^)]*request\.
# httpx
httpx\.(get|post|put|delete)\s*\([^)]*request\.Authentication Issues
Weak Password Policy
len\s*\(\s*password\s*\)\s*>=?\s*[1-7]\b
if\s+len\s*\(\s*password\s*\)\s*<\s*[2-7]:
MIN_PASSWORD_LENGTH\s*=\s*[1-7]\bSession Issues
# Session in cookies without secure flag
SESSION_COOKIE_SECURE\s*=\s*False
SESSION_COOKIE_HTTPONLY\s*=\s*False
# Flask session secret
app\.secret_key\s*=\s*['"][^'"]+['"]
# Debug mode
DEBUG\s*=\s*True
app\.run\s*\([^)]*debug\s*=\s*TrueDjango-Specific
Security Settings
# Dangerous settings
DEBUG\s*=\s*True
ALLOWED_HOSTS\s*=\s*\[['"]?\*['"]?\]
CSRF_COOKIE_SECURE\s*=\s*False
SESSION_COOKIE_SECURE\s*=\s*False
SECURE_SSL_REDIRECT\s*=\s*FalseTemplate Issues
# Unescaped output
\{\{[^}]*\|safe\}\}
mark_safe\s*\(
format_html\s*\([^)]*\+ORM Issues
# Raw SQL
\.raw\s*\(
\.extra\s*\(
RawSQL\s*\(
cursor\.execute\s*\(Flask-Specific
Security Issues
# Debug mode
app\.run\s*\([^)]*debug\s*=\s*True
FLASK_DEBUG\s*=\s*1
# Secret key
app\.secret_key\s*=\s*['"]
# Template injection
render_template_string\s*\([^)]*request\.FastAPI-Specific
Security Issues
# Debug/docs in production
app\s*=\s*FastAPI\s*\([^)]*docs_url
app\s*=\s*FastAPI\s*\([^)]*redoc_url
# Missing auth on endpoints
@app\.(get|post|put|delete)\s*\([^)]*\)\s*\n(async\s+)?def\s+\w+\s*\([^)]*\)(?!.*Depends)Logging Issues
# Sensitive data in logs
(logging|logger)\.\w+\s*\([^)]*password
(logging|logger)\.\w+\s*\([^)]*secret
(logging|logger)\.\w+\s*\([^)]*token
(logging|logger)\.\w+\s*\([^)]*api_key
print\s*\([^)]*password
print\s*\([^)]*secretRegex Denial of Service
# Nested quantifiers
re\.compile\s*\([^)]*(\+|\*)[^)]*(\+|\*)
re\.(match|search|findall)\s*\([^)]*(\+|\*)[^)]*(\+|\*)Secure Patterns (False Positive Filtering)
# Parameterized queries
cursor\.execute\s*\([^)]*,\s*\[
cursor\.execute\s*\([^)]*,\s*\(
%s[^%]*,\s*\(
# Secure random
secrets\.token_
secrets\.choice\s*\(
os\.urandom\s*\(
random\.SystemRandom\s*\(
# Safe YAML
yaml\.safe_load\s*\(
yaml\.load\s*\([^)]*Loader\s*=\s*yaml\.SafeLoader
# Input sanitization
bleach\.clean\s*\(
escape\s*\(
quote\s*\(Common Security Remediation Guide
Quick-reference fixes for common vulnerabilities.
Injection Prevention
SQL Injection
Use parameterized queries:
// Node.js (mysql2)
const [rows] = await conn.execute(
'SELECT * FROM users WHERE id = ? AND status = ?',
[userId, 'active']
);
// Node.js (pg)
const result = await client.query(
'SELECT * FROM users WHERE id = $1',
[userId]
);# Python (psycopg2)
cursor.execute(
"SELECT * FROM users WHERE id = %s AND status = %s",
(user_id, 'active')
)
# Python (SQLAlchemy)
session.query(User).filter(User.id == user_id).first()Command Injection
Avoid shell execution:
# VULNERABLE
os.system(f"ping {ip_address}")
# SECURE
import subprocess
subprocess.run(['ping', '-c', '1', ip_address], shell=False)// VULNERABLE
exec(`ping ${ip}`);
// SECURE
const { spawn } = require('child_process');
spawn('ping', ['-c', '1', ip]);XSS Prevention
Escape output:
// React (automatic escaping)
function Safe({ userInput }) {
return <div>{userInput}</div>;
}
// Manual escaping
function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}---
Cryptography Fixes
Password Hashing
Use bcrypt, Argon2, or scrypt:
// Node.js
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash(password, 12);
const valid = await bcrypt.compare(password, hash);# Python
import bcrypt
hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
valid = bcrypt.checkpw(password.encode(), hash)Secure Random Generation
// Node.js
const crypto = require('crypto');
const token = crypto.randomBytes(32).toString('hex');
const uuid = crypto.randomUUID();# Python
import secrets
token = secrets.token_hex(32)
safe_choice = secrets.choice(allowed_values)Secure Encryption
// AES-256-GCM
const crypto = require('crypto');
function encrypt(text, key) {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return {
iv: iv.toString('hex'),
encrypted,
tag: cipher.getAuthTag().toString('hex')
};
}---
Authentication Fixes
Strong Password Policy
const passwordPolicy = {
minLength: 12,
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
requireSpecial: true
};
function validatePassword(password) {
if (password.length < 12) return false;
if (!/[A-Z]/.test(password)) return false;
if (!/[a-z]/.test(password)) return false;
if (!/[0-9]/.test(password)) return false;
if (!/[!@#$%^&*]/.test(password)) return false;
return true;
}Secure Session Configuration
// Express session
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: true, // HTTPS only
httpOnly: true, // No JS access
sameSite: 'strict', // CSRF protection
maxAge: 3600000 // 1 hour
}
}));Rate Limiting
const rateLimit = require('express-rate-limit');
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts
message: 'Too many login attempts'
});
app.post('/login', loginLimiter, loginHandler);---
Access Control Fixes
Authorization Middleware
function requireAuth(req, res, next) {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
}
function requireRole(...roles) {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
}
// Usage
app.get('/admin', requireAuth, requireRole('admin'), handler);Resource Ownership Verification
async function getOrder(req, res) {
const order = await Order.findOne({
_id: req.params.id,
userId: req.user.id // Ownership check
});
if (!order) {
return res.status(404).json({ error: 'Not found' });
}
res.json(order);
}CORS Configuration
const cors = require('cors');
app.use(cors({
origin: ['https://app.example.com'],
methods: ['GET', 'POST'],
credentials: true
}));---
Path Traversal Fix
const path = require('path');
function safePath(basePath, userInput) {
// Remove any path separators
const filename = path.basename(userInput);
const fullPath = path.resolve(basePath, filename);
// Verify still within base
if (!fullPath.startsWith(path.resolve(basePath))) {
throw new Error('Invalid path');
}
return fullPath;
}---
SSRF Prevention
const { URL } = require('url');
function isAllowedUrl(urlString) {
try {
const url = new URL(urlString);
// Block internal networks
const blockedPatterns = [
/^localhost$/i,
/^127\./,
/^10\./,
/^172\.(1[6-9]|2[0-9]|3[01])\./,
/^192\.168\./,
/^169\.254\./,
/^0\.0\.0\.0$/
];
for (const pattern of blockedPatterns) {
if (pattern.test(url.hostname)) {
return false;
}
}
// Only allow HTTPS
if (url.protocol !== 'https:') {
return false;
}
return true;
} catch {
return false;
}
}---
Security Headers
const helmet = require('helmet');
app.use(helmet());
// Or configure individually:
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
}
}));
app.use(helmet.hsts({
maxAge: 31536000,
includeSubDomains: true
}));---
Input Validation
const Joi = require('joi');
const userSchema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(12).required(),
age: Joi.number().integer().min(0).max(150)
});
function validateInput(req, res, next) {
const { error } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}
next();
}---
Secrets Management
// Use environment variables
const apiKey = process.env.API_KEY;
const dbPassword = process.env.DB_PASSWORD;
// Never commit secrets
// Use .env files for development only
// Use secrets manager in production (AWS Secrets Manager, Vault, etc.)Example .env (add to .gitignore):
API_KEY=your-api-key
DB_PASSWORD=your-db-password---
Quick Reference
| Vulnerability | Primary Fix |
|---|---|
| SQL Injection | Parameterized queries |
| XSS | Output encoding |
| Command Injection | Avoid shell, use arrays |
| Weak Crypto | bcrypt/Argon2, AES-GCM |
| Hardcoded Secrets | Environment variables |
| SSRF | URL allowlist |
| Path Traversal | Validate paths |
| Missing Auth | Middleware enforcement |
| Weak Sessions | Secure cookie flags |
Related skills
FAQ
What does security-scan check?
security-scan runs structured scans on codebases and configs before release, surfacing dependency vulnerabilities, insecure defaults, exposed secrets patterns, and compliance gaps with severity-ranked remediation guidance for developers.
When should developers run security-scan?
Developers should invoke security-scan before shipping release candidates, when inheriting unfamiliar repositories, or when audit stakeholders request documented vulnerability and misconfiguration review across the project tree.