api-design
Use when designing or reviewing a public API, exported function signature, module boundary, exported type/interface, or any contract other code depends on
Use when writing or reviewing code that parses user input, builds SQL/shell commands, handles secrets/credentials, hashes passwords, changes auth checks, deserializes untrusted data, or constructs paths/URLs from input
$ npx -y skills add oribarilan/97 --skill security-and-trust-boundaries --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/security-and-trust-boundariesContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when writing or reviewing code that parses user input, builds SQL/shell commands, handles secrets/credentials, hashes passwords, changes auth checks, deserializes untrusted data, or constructs paths/URLs from input
name: security-and-trust-boundaries description: Use when writing or reviewing code that parses user input, builds SQL/shell commands, handles secrets/credentials, hashes passwords, changes auth checks, deserializes untrusted data, or constructs paths/URLs from input
Common security mistakes grouped by trust boundary: input concatenated into a query, a token logged "for debugging", an unguarded endpoint, `pickle.loads` on untrusted bytes. **When code crosses a trust boundary, stop and run the matching checks before you commit.**
This is a **rigid** skill. Jump to the sub-section that matches what you're writing and run that sub-section's checks.
These checks matter most when untrusted input is crossing into a system with real users — production endpoint, shared service, anything that touches user data, secrets, or auth state. In MVPs, prototypes, internal dev tools, and one-off scripts, prefer the simplest thing that works and re-invoke this skill before the code reaches users. **Three rules apply at every stage, even prototypes: no committed credentials in source, no string-built SQL or shell commands, no `pickle.loads` (or equivalent) on untrusted input. Surface these in your summary to the user even in throwaway code.**
The rules below describe properties of code that crosses a trust boundary, whether you authored that code or encountered it in a file you are touching. When you find an issue in pre-existing code adjacent to your edit, surface it in your summary to the user — don't silently rewrite the file outside the scope you were asked to change.
Invoke when you're about to:
If the change touches one of these domains even slightly, **invoke anyway** — the per-domain check is short and the bugs are not.
1. **Parameterize, never concatenate.** SQL: use bound parameters (`cursor.execute("SELECT * FROM u WHERE id = ?", (uid,))`), not f-strings or `+`. NoSQL: use the driver's typed query API, not string-templated JSON. LDAP: escape per RFC 4515 with the driver's helper, not by hand. Command: pass an argv list, not a shell string. Example: `cursor.execute(f"SELECT * FROM users WHERE name = '{name}'")` is exploitable by any user setting their name to `' OR '1'='1`. 2. **`shell=False` is the default; `shell=True` is a vulnerability.** Use `subprocess.run(["git", "clone", url], shell=False)` (argv form), not `subprocess.run(f"git clone {url}", shell=True)`. The argv form passes arguments straight to the kernel; the shell form runs a shell first, which expands `$(...)`, backticks, `;`, `|`, `&&`, globs, and substitutions in attacker-controlled strings. If a shell genuinely is required (rare), every interpolated value must be passed through the language's shell-quoting helper (`shlex.quote`, etc.) — and you should re-justify why a shell is required. 3. **Template engines auto-escape; raw concatenation does not.** Building HTML, SQL, JSON, or any structured output by `+` or f-string puts the structure-vs-data decision on the developer. Use a template engine with auto-escaping on (Jinja2, ERB with safe defaults, parameterized JSON builders), or generate via the language's typed AST (LXML for XML, the JSON library for JSON). The legitimate exception is templating a known-constant string, never user input.
4. **Path traversal: validate to a known root.** `open(os.path.join(BASE, user_filename))` is a vulnerability if `user_filename` can be `../../etc/passwd`. Resolve to a real path and verify the result starts with the intended root (`os.path.realpath(p).startswith(os.path.realpath(BASE) + os.sep)`). Reject `..`, absolute paths, null bytes, alternate path separators, and Windows device names (`CON`, `NUL`, `AUX`). 5. **SSRF: don't fetch arbitrary URLs from input.** Server-side `requests.get(user_url)` lets the attacker pivot into your VPC, hit metadata services (`169.254.169.254`), and read internal endpoints. If you must fetch user-supplied URLs, allowlist the scheme and host (or DNS-resolve and reject private/loopback/link-local ranges) and disable redirects (`allow_redirects=False`). 6. **Deserialization: only on trusted sources, only with a safe loader.** `pickle.loads`, `yaml.load` (without `Sa
Agent skills distilled from the hard-won lessons of world-renowned programmers, in the spirit of "97 Things Every Programmer Should Know"
Repo: oribarilan/97
Use when designing or reviewing a public API, exported function signature, module boundary, exported type/interface, or any contract other code depends on
Use when considering, evaluating, or performing a refactor, restructure, cross-file rename, or cleanup
Use when writing, reviewing, or changing build scripts, CI workflows, deploy pipelines, repo setup, or evaluating a new tool/dependency
Use when writing or reviewing functions, classes, naming, or non-trivial logic (≥3 lines)
Use when writing or reviewing error handling, floating-point math, concurrent code, remote calls, singletons/globals, hot-path data structures, or high-volume…
Use when introducing, reviewing, or renaming a top-level type, table, or domain concept; or choosing where state lives (in-memory vs persistent)