From security
Provides fix patterns for SQL, command, and XSS injection vulnerabilities with vulnerable/secure code examples in Python (SQLAlchemy/psycopg2), JavaScript/TypeScript (Node.js/Prisma/Knex), and Java (JDBC).
npx claudepluginhub zate/cc-plugins --plugin securityThis skill uses the workspace's default tool permissions.
Actionable fix patterns for injection-based security vulnerabilities.
Explains root cause of injection vulnerabilities (SQLi, XSS, command injection) as untrusted data interpreted as code. Guides reviews of user input in queries, commands, markup; audits across tech stacks.
Detects SQL injection vulnerabilities by tracing user inputs through code to database queries, flagging unsafe patterns like concatenation and unparameterized ORMs. Scans frameworks including Django, Rails, Express, Go.
Detects SQL, command, template, and code injection vulnerabilities from unsanitized user input. Flags patterns like query concatenation or eval, recommends parameterized queries, argument lists, and autoescaping templates.
Share bugs, ideas, or general feedback.
Actionable fix patterns for injection-based security vulnerabilities.
User input directly concatenated into SQL queries allows attackers to manipulate database queries.
Don't:
# VULNERABLE: String concatenation
def get_user_bad(user_id):
query = f"SELECT * FROM users WHERE id = '{user_id}'"
cursor.execute(query)
return cursor.fetchone()
# VULNERABLE: Format strings
query = "SELECT * FROM users WHERE name = '%s'" % username
Do:
# SECURE: Parameterized queries with psycopg2
def get_user_safe(user_id):
query = "SELECT * FROM users WHERE id = %s"
cursor.execute(query, (user_id,))
return cursor.fetchone()
# SECURE: SQLAlchemy ORM
def get_user_orm(user_id):
return db.session.query(User).filter(User.id == user_id).first()
# SECURE: SQLAlchemy with text() and bindparams
from sqlalchemy import text
query = text("SELECT * FROM users WHERE id = :user_id")
result = db.session.execute(query, {"user_id": user_id})
Don't:
// VULNERABLE: String concatenation
const query = `SELECT * FROM users WHERE id = '${userId}'`;
db.query(query);
// VULNERABLE: Template literals
const sql = `SELECT * FROM products WHERE name LIKE '%${searchTerm}%'`;
Do:
// SECURE: Parameterized queries (mysql2)
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);
// SECURE: Parameterized with named placeholders (pg)
const query = 'SELECT * FROM users WHERE id = $1';
await client.query(query, [userId]);
// SECURE: Prisma ORM
const user = await prisma.user.findUnique({
where: { id: userId }
});
// SECURE: Knex.js query builder
const user = await knex('users').where('id', userId).first();
Don't:
// VULNERABLE: String concatenation
String query = "SELECT * FROM users WHERE id = '" + userId + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
Do:
// SECURE: PreparedStatement
String query = "SELECT * FROM users WHERE id = ?";
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setString(1, userId);
ResultSet rs = pstmt.executeQuery();
// SECURE: JPA/Hibernate with named parameters
@Query("SELECT u FROM User u WHERE u.id = :userId")
User findByUserId(@Param("userId") String userId);
Don't:
// VULNERABLE: fmt.Sprintf in queries
query := fmt.Sprintf("SELECT * FROM users WHERE id = '%s'", userID)
rows, err := db.Query(query)
Do:
// SECURE: Parameterized queries
query := "SELECT * FROM users WHERE id = $1"
rows, err := db.Query(query, userID)
// SECURE: With sqlx
var user User
err := db.Get(&user, "SELECT * FROM users WHERE id = $1", userID)
ASVS: V1.2.1, V1.2.2 References: OWASP SQL Injection Prevention
User input passed to shell commands allows attackers to execute arbitrary system commands.
Don't:
# VULNERABLE: shell=True with user input
import subprocess
subprocess.run(f"grep {pattern} {filename}", shell=True)
# VULNERABLE: os.system
import os
os.system(f"convert {input_file} {output_file}")
Do:
# SECURE: subprocess with argument list (no shell)
import subprocess
import shlex
result = subprocess.run(
['grep', pattern, filename],
capture_output=True,
text=True
)
# SECURE: If shell is required, use shlex.quote
if shell_required:
safe_filename = shlex.quote(filename)
subprocess.run(f"process {safe_filename}", shell=True)
# SECURE: Use libraries instead of shell commands
from PIL import Image
img = Image.open(input_file)
img.save(output_file)
Don't:
// VULNERABLE: exec with user input
const { exec } = require('child_process');
exec(`grep ${pattern} ${filename}`);
// VULNERABLE: String interpolation in shell command
exec(`convert ${inputFile} ${outputFile}`);
Do:
// SECURE: execFile with argument array
const { execFile } = require('child_process');
execFile('grep', [pattern, filename], (error, stdout) => {
console.log(stdout);
});
// SECURE: spawn with arguments
const { spawn } = require('child_process');
const grep = spawn('grep', [pattern, filename]);
// SECURE: Use libraries instead of shell commands
const sharp = require('sharp');
await sharp(inputFile).toFile(outputFile);
Don't:
// VULNERABLE: Runtime.exec with concatenation
String cmd = "grep " + pattern + " " + filename;
Runtime.getRuntime().exec(cmd);
Do:
// SECURE: ProcessBuilder with argument list
ProcessBuilder pb = new ProcessBuilder("grep", pattern, filename);
pb.redirectErrorStream(true);
Process process = pb.start();
ASVS: V1.2.3 References: OWASP OS Command Injection
User input rendered in HTML without proper encoding allows script injection.
Don't:
// VULNERABLE: innerHTML with user input
element.innerHTML = userInput;
// VULNERABLE: document.write
document.write(userData);
// VULNERABLE: jQuery html()
$('#content').html(userInput);
Do:
// SECURE: textContent for plain text
element.textContent = userInput;
// SECURE: DOMPurify for HTML content
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userHtml);
// SECURE: Create elements programmatically
const link = document.createElement('a');
link.href = sanitizeUrl(userUrl);
link.textContent = userText;
parent.appendChild(link);
// SECURE: jQuery text()
$('#content').text(userInput);
Don't:
// VULNERABLE: dangerouslySetInnerHTML without sanitization
function Comment({ content }) {
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}
// VULNERABLE: href with user input (javascript: URLs)
<a href={userUrl}>Click here</a>
Do:
// SECURE: React auto-escapes by default
function Comment({ content }) {
return <div>{content}</div>;
}
// SECURE: Sanitize if HTML is required
import DOMPurify from 'dompurify';
function RichContent({ html }) {
const clean = DOMPurify.sanitize(html);
return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}
// SECURE: Validate URLs
function SafeLink({ url, text }) {
const isValid = /^https?:\/\//.test(url);
if (!isValid) return <span>{text}</span>;
return <a href={url}>{text}</a>;
}
Don't:
# VULNERABLE: Marking as safe without sanitization
from markupsafe import Markup
return Markup(f"<div>{user_input}</div>")
# VULNERABLE: Disabling autoescaping
{% autoescape false %}
{{ user_content }}
{% endautoescape %}
Do:
# SECURE: Let Jinja2 auto-escape (default)
return render_template('page.html', content=user_input)
# Template: auto-escaped by default
<div>{{ content }}</div>
# SECURE: Use bleach for allowing specific HTML
import bleach
allowed_tags = ['b', 'i', 'u', 'a']
allowed_attrs = {'a': ['href']}
clean = bleach.clean(user_html, tags=allowed_tags, attributes=allowed_attrs)
ASVS: V3.3.1, V1.3.1 References: OWASP XSS Prevention
| Vulnerability | Fix Pattern | Key Libraries |
|---|---|---|
| SQL Injection | Parameterized queries | ORM, prepared statements |
| Command Injection | Argument arrays, no shell | subprocess, execFile |
| XSS | Auto-escaping, sanitization | DOMPurify, bleach |
remediation-crypto - Cryptography fixesremediation-auth - Authentication/authorization fixesremediation-config - Configuration fixesvulnerability-patterns - Detection patterns