Claude-kit security-hygiene
Baseline security rules across Python, TypeScript, Rust, and C — secrets management, input validation, safe memory patterns, and dependency hygiene
git clone https://github.com/ryypow/claude-kit
T=$(mktemp -d) && git clone --depth=1 https://github.com/ryypow/claude-kit "$T" && mkdir -p ~/.claude/skills && cp -r "$T/base/skills/security-hygiene" ~/.claude/skills/ryypow-claude-kit-security-hygiene && rm -rf "$T"
base/skills/security-hygiene/SKILL.mdOverview
This skill covers the non-negotiable security rules that apply to every project regardless of domain. These are not aspirational guidelines — they are minimum standards that prevent the most common categories of security incidents.
Secrets Management
Rule: No secrets in source code. Ever.
Secrets include: API keys, tokens, passwords, private keys, connection strings with credentials, webhook URLs with auth tokens.
Where secrets go:
- Environment variables (loaded via
files that are gitignored).env - Secret managers (AWS Secrets Manager, Vault, GCP Secret Manager)
- CI/CD secret stores (GitHub Actions secrets, GitLab CI variables)
How to detect:
- High-entropy strings (base64, hex) longer than 20 characters
- Patterns:
,sk-
,pk_
,ghp_
,AKIA
,-----BEGINBearer - Variable names containing:
,key
,token
,secret
,password
,credentialauth
If a secret is committed:
- Rotate the secret immediately — assume it is compromised
- Remove it from the code and commit the removal
- The secret remains in git history even after removal — rotation is mandatory
Input Validation
Rule: Validate all external input at system boundaries.
External input includes: user form data, query parameters, request bodies, file uploads, API responses from third parties, environment variables, command-line arguments, file contents.
Validation strategy:
| Language | Approach |
|---|---|
| Python | Pydantic models, dataclasses with validation, manual type checks |
| TypeScript | Zod schemas, io-ts, manual validation functions |
| Rust | Type system + serde deserialization with validation |
| C | Manual bounds checking on every buffer, null checks on every pointer |
What to validate:
- Type: is it the expected type?
- Range: is it within acceptable bounds? (string length, number range, date range)
- Format: does it match the expected pattern? (email, URL, UUID)
- Content: does it contain disallowed characters? (SQL metacharacters, script tags)
Injection Prevention
SQL Injection
Never do this:
query = f"SELECT * FROM users WHERE id = {user_input}"
Always do this:
cursor.execute("SELECT * FROM users WHERE id = %s", (user_input,))
Use parameterized queries in every language. No exceptions. ORMs handle this automatically — raw queries need manual parameterization.
Command Injection
Never do this:
os.system(f"convert {filename} output.png")
Always do this:
subprocess.run(["convert", filename, "output.png"], shell=False)
Never pass user input to
shell=True, exec, eval, or system(). Use array-form subprocess calls that don't invoke a shell.
XSS (Cross-Site Scripting)
- Escape all user-generated content before rendering in HTML
- Use framework-provided escaping (React's JSX auto-escapes, Django's template engine auto-escapes)
- Never use
,innerHTML
, ordangerouslySetInnerHTML
with user inputv-html - Content-Security-Policy headers as defense in depth
Memory Safety (C/Rust)
C — Banned Functions
These functions are banned because they have no bounds checking:
| Banned | Safe Alternative |
|---|---|
| |
| or |
| |
| with width limit |
| |
C — Required Patterns
- Every
must have a null check and a correspondingmalloc()
on every code pathfree() - Every buffer must have explicit size tracking — no "just assume it's big enough"
- All array accesses must be bounds-checked
- All string operations must use bounded variants
Rust — Required Patterns
blocks must have aunsafe
comment explaining the invariant that makes this safe// SAFETY:- No
in library code — useunwrap()
operator or explicit error handling? - Prefer
lint levelclippy::pedantic
Dependency Hygiene
Rules
- Pin dependencies — use lock files (
,package-lock.json
,Cargo.lock
,poetry.lock
with pinned versions). Commit lock files.requirements.txt - No floating versions in production —
is a floating version. Pin to exact:"express": "^4.18"
or rely on the lock file."express": "4.18.2" - Review new dependencies — before adding a dependency, check: active maintenance, known vulnerabilities, license compatibility, size/footprint.
- Minimize dependency count — every dependency is an attack surface. If you can do it in 10 lines of code, don't add a package.
eval() and Dynamic Execution
Rule: No eval() in any language. No exceptions.
| Language | Banned | Why |
|---|---|---|
| JavaScript | , , | Arbitrary code execution |
| Python | , , with user input | Arbitrary code execution |
| Ruby | , with user input | Arbitrary code execution |
If you think you need
eval(), you don't. Use JSON.parse() for data, a proper parser for expressions, or a sandboxed interpreter for user code.
When NOT to apply this skill
- These rules have no exceptions for prototypes, spikes, or "just testing." Security mistakes in prototypes become security mistakes in production when the prototype ships.