| name | security |
| description | Security checklist for code review and implementation. Covers input escaping, injection prevention, path traversal, process safety, dependency integrity, and secrets management. Load when working on user-facing code, template rendering, or process spawning. |
Security Skill
Defensive coding practices. Apply these checks during implementation and review.
Input Escaping
Never interpolate user input into templates, scripts, or SQL
let js = format!("var id = '{}';", user_input);
fn escape_js_string(s: &str) -> String {
s.replace('\\', "\\\\")
.replace('\'', "\\'")
.replace('"', "\\\"")
.replace('<', "\\x3c")
.replace('>', "\\x3e")
.replace('\n', "\\n")
.replace('\r', "\\r")
}
let js = format!("var id = '{}';", escape_js_string(user_input));
const html = `<div>${userInput}</div>`;
function escapeHtml(s: string): string {
return s.replace(/&/g, "&").replace(/</g, "<")
.replace(/>/g, ">").replace(/"/g, """);
}
const html = `<div>${escapeHtml(userInput)}</div>`;
Context matters — escape for the target language
| Context | Escape | Characters |
|---|
| HTML body | HTML entities | & < > " |
| HTML attribute | HTML entities + quote | & < > " ' |
| JavaScript string | JS escapes | \ ' " < > \n \r |
| URL parameter | encodeURIComponent | All non-unreserved |
| SQL | Parameterized queries | Never interpolate |
| Shell command | Avoid if possible | Use spawn(cmd, [args]) not exec(string) |
Path Traversal
Validate that resolved paths stay within the expected root
const filePath = join(rootDir, userInput);
const resolved = resolve(rootDir, userInput);
if (!resolved.startsWith(resolve(rootDir) + sep) && resolved !== resolve(rootDir)) {
throw new Error("Path traversal attempt");
}
let path = root.join(&user_path);
let canonical = path.canonicalize()?;
if !canonical.starts_with(&root.canonicalize()?) {
return Err("Path traversal".into());
}
Reject suspicious path components
.. segments
- Null bytes (
%00, \0)
- Absolute paths when relative expected
- Symlinks that escape the root (use
canonicalize/realpath)
Process Spawning
Use spawn with argument arrays, never shell interpolation
execSync(`grep ${userInput} file.txt`);
spawn("grep", [userInput, "file.txt"], { stdio: "pipe" });
Never use stdio: "inherit" in TUI applications
Inherited stdio corrupts the terminal UI. Always use "pipe" or "ignore".
spawn("some-tool", [], { stdio: "inherit" });
spawn("some-tool", [], { stdio: "pipe" });
spawn("some-tool", [], { stdio: "ignore" });
Limit pkill/killall scope
execSync("pkill -f 'ollama serve'");
if (child) { child.kill("SIGTERM"); child = null; }
Set timeouts on child processes
const child = spawn("cmd", args);
const timer = setTimeout(() => {
child.kill("SIGTERM");
}, 300_000);
child.on("exit", () => clearTimeout(timer));
Dependency Integrity
Pin CDN resources with Subresource Integrity (SRI)
<script src="https://cdn.example.com/lib.js"></script>
<script src="https://cdn.example.com/lib.js"
integrity="sha384-abc123..."
crossorigin="anonymous"></script>
Prefer bundling over CDN for offline-first tools
const JS: &str = include_str!("../static/lib.min.js");
import { force } from "force-graph";
Secrets Management
- Never hardcode secrets — use environment variables or secret managers.
- Never log secrets — mask or omit sensitive values from log output.
- Never commit secrets — use
.gitignore and pre-commit hooks.
- Rotate on exposure — if a secret appears in a commit, rotate immediately.
const apiKey = "sk-abc123";
const apiKey = process.env.API_KEY;
if (!apiKey) throw new Error("API_KEY not set");
TOCTOU (Time-of-Check to Time-of-Use)
When you check a condition and then act on it, the condition may change between check and action.
if (existsSync(path)) {
const data = readFileSync(path);
}
try {
const data = readFileSync(path);
} catch (err) {
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
} else throw err;
}
Checklist
Before submitting code that handles external input: