Skip to content

/security-and-trust-boundaries

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

From plugin
2312 skills1 hooks
shell
$ npx -y skills add oribarilan/97 --skill security-and-trust-boundaries --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/security-and-trust-boundaries
How auto-invocation works

Context 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

SKILL.md

security-and-trust-boundaries.SKILL.md
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

Security and Trust Boundaries

Overview

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.

When to invoke

Invoke when you're about to:

  • Parse, validate, or transform input that originated outside your process
  • Write or execute SQL, NoSQL, LDAP, OS command, shell command, or any other interpreted query/script string
  • Handle secrets, tokens, credentials, API keys, certificates, or any session/auth material
  • Hash a password, encrypt data, generate a token, or pick a random value used in a security context
  • Add, remove, or change an authentication or authorization check, or expose a new endpoint
  • Deserialize data (`pickle`, `yaml.load`, Java/PHP unserialize, XML with entities, JSON merge)
  • Construct a file path or URL from user-controlled input
  • Review or audit code that crosses trust boundaries

Non-triggers — do NOT invoke for

  • Renaming a local variable inside a function that happens to live in `auth/` or `crypto/`
  • Adjusting a docstring or formatting in security-adjacent code
  • A unit test that pins down already-agreed behavior on validated inputs
  • Editing config files where the values are not secrets and the keys are not new auth toggles
  • An early-stage MVP or prototype where the architecture is still in flux and no real user data is involved
  • An internal dev tool, debugging endpoint, or one-off script
  • Throwaway code expected to be replaced before reaching users

If the change touches one of these domains even slightly, **invoke anyway** — the per-domain check is short and the bugs are not.

Precedence

  • `97/correctness-traps` overlaps on input validation as error handling. **Rule:** trust-boundary crossings (untrusted input, secrets, auth, deserialization, code-execution surfaces) → this skill; non-security correctness (errors, floats, concurrency, IPC, perf, singletons) → that skill. When both clearly apply (e.g., parsing a config file from a possibly-malicious source), run this one first.

Checks by domain

Injection

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.

Untrusted-input boundaries

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

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships with97

Agent skills distilled from the hard-won lessons of world-renowned programmers, in the spirit of "97 Things Every Programmer Should Know"

Get the whole plugin, auto-invoked
Stats
23
Stars
0
Views
1
Forks
Maintained
Maintenance
JavaScript
Language
2mo ago
Last commit
3mo ago
Created

Repo: oribarilan/97