From agentic-security
Refuses SQL, NoSQL, LDAP, and XPath queries that concatenate user input. Suggests parameterized replacements for PostgreSQL, MySQL, Prisma, SQLAlchemy, and more.
How this skill is triggered — by the user, by Claude, or both
Slash command
/agentic-security:security-sql-injection-warnThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Activates **before** you write SQL that interpolates user input into the
Activates before you write SQL that interpolates user input into the query string. This is CWE-89 — every year, the #1 or #2 OWASP entry. The correct fix is parameterized queries; the wrong fix is "validate the input first" (regex bypasses are a defining feature of this bug class).
You're about to call Edit / Write with a body that contains any of:
db.query(\SELECT * FROM users WHERE id = ${id}`), connection.execute(f"SELECT * FROM x WHERE id = {id}"), cursor.execute("SELECT * FROM x WHERE id = '" + id + "'")`.prisma.$queryRaw\…${user}…`(NOTPrisma.sql`…`, which is safe), User.objects.raw("SELECT … WHERE " + col + " = …"), sequelize.query(`…${user}…`)`.db.users.find({ name: req.body.name }) where req.body.name is an
object — $where, $ne, $gt operators leak through. Mongoose's
.find(req.body) is the canonical version.ldap.search('(uid=' + user + ')').xpath.evaluate("//user[@name='" + name + "']", …).SELECT * FROM x ORDER BY ${userColumn} — even allow-listed columns
need to be hard-coded, not string-built.Stop. Refuse the edit. Propose the parameterized form.
Name the vuln class. "CWE-89 / SQL Injection. The query string
cannot contain user input. Even one ${x} interpolation breaks it."
Show the literal replacement for the user's exact database driver. Three flavors:
pg: db.query('SELECT … WHERE id = $1', [id])mysql2: db.execute('SELECT … WHERE id = ?', [id])psycopg: cur.execute("SELECT … WHERE id = %s", (id,))session.execute(text("SELECT … WHERE id = :id"), {"id": id})prisma.user.findUnique({ where: { id } }) — or use
Prisma.sql\…`if you must use raw, NEVER$queryRaw`…``.For ORDER BY / column-name parameters (the one shape parameterized queries DON'T solve): show the allow-list pattern:
const ALLOWED = new Set(['id', 'name', 'created_at']);
if (!ALLOWED.has(col)) throw new Error('invalid sort column');
const sql = `SELECT * FROM x ORDER BY ${col}`;
Hard-code the allow-list. Never derive it from user input.
For NoSQL: refuse object-shaped query inputs. Always cast
req.body.x to a string with String(req.body.x).slice(0, MAX)
before passing to the query.
/setup --bodyguard — block sqli shapes at Edit time/scan --all — pick up unprotected concats already in the codebase/triage --explain CWE-89 — full SQLi explanation, attacker scenarios/fix --one <id> — apply the parameterized-query fixnpx claudepluginhub clear-capabilities/agentic-security --plugin agentic-securityPrevents SQL injection by enforcing parameterized queries and ORM usage over string concatenation. Useful when constructing database queries from user input, API params, or external data.
Prevents SQL, NoSQL, and command injection by enforcing parameterized queries, input validation, and safe shell execution patterns.
Detects SQL, command, and template injection caused by user input reaching an interpreter without parameterization. Checks concatenated query strings, shell commands, eval/exec calls, and unsafe template usage.