When modifying code, configuration, infrastructure, or dependencies, apply these principles before making changes. Assume hostile input, compromised dependencies, misconfigured infrastructure, and least privilege by default.
Before writing or modifying code, identify:
- What crosses a trust boundary?
- User input → backend
- Service A → service B
- CLI argument → shell
- File upload → parser
- Webhook → internal workflow
- Database value → query/template/command
- Isvalidation performed at the boundary, not buried deep in business logic?
- Can errors, logs, or responses leak sensitive data back across the boundary? Rule: Data that crosses a trust boundary is untrusted until explicitly validated.
For every input surface, including HTTP, CLI, environment variables, files, IPC, queues, webhooks, and database values reused in queries:
- Prefer allowlists over denylists.
- Validate type, length, format, range, and encoding before use.
- Parameterize queries.
- Never concatenate untrusted data into SQL, LDAP, XPath, HTML, templates, or shell commands.
- Treat file paths as untrusted.
- Resolve paths and jail them to an expected root before file access.
- Normalize input before validation when equivalent encodings may exist.
Red flags to flag and fix:
- String interpolation into SQL, shell, HTML, templates, LDAP, or XPath
- Unvalidated redirects or forwards
- Path traversal risk through filenames, archive extraction, or user-controlled paths
- SSRF through user-controlled URLs
- Unsafe deserialization
- User-controlled regex patterns
- User-controlled template rendering
When touching auth-related code:
- Treat authentication and authorization as separate checks.
- Authentication: who is the caller?
- Authorization: what is the caller allowed to do?
- Default to deny.
- Use explicit grants only.
- Never implement custom crypto, token formats, password storage, or auth protocols unless explicitly required and reviewed.
- Use established, maintained libraries.
- Session tokens must be random, long, and generated using a CSPRNG.
- Invalidate sessions server-side on logout, credential rotation, or privilege changes.
- Enforce authorization close to the protected resource, not only at the routing or controller layer.
Rule: If a function touches a protected resource, it must either enforce permissions itself or clearly document the upstream permission invariant it depends on.
- Never hardcode secrets, API keys, passwords, tokens, private keys, or signing keys in source code or config files.
- Use environment variables, secret stores, or managed secret systems.
- Reference secrets by name only.
- Do not print secrets in logs, errors, traces, telemetry, metrics, or test snapshots.
- Mask sensitive values before logging.
- Exclude secret-bearing files from version control using
.gitignore,.dockerignore,.claudeignore, or equivalent. - Rotate secrets if exposure is suspected.
On discovery: If a hardcoded secret is found, stop and flag it immediately. Do not silently move, reuse, or normalize it.
When creating or modifying permissions:
- File permissions should default to
600or640. - Avoid
777. - Database users should receive only the tables and operations required.
- Cloud IAM roles should be scoped to the minimum required actions and resources.
- Processes should drop privileges as early as possible.
- Do not run as root unless unavoidable and justified.
- Services should bind only to required interfaces.
- Unused ports should remain closed.
- CI/CD tokens should be scoped to the narrowest repository, environment, and operation possible.
Rule: Every permission must have a specific reason to exist.
When adding or updating dependencies:
- Prefer actively maintained packages with a clear release history.
- Pin versions in lock files.
- Avoid broad production version ranges.
- Review packages that require filesystem, network, subprocess, native-extension, or post-install script access.
- Avoid
curl | bash, remote install scripts, or unaudited binary downloads unless explicitly approved and reviewed. - Check whether the dependency is actually necessary before adding it.
- Prefer standard-library or already-approved internal alternatives when reasonable.
Rule: Every new dependency expands the attack surface.
Use modern, reviewed primitives and libraries.
Acceptable examples:
- Encryption: AES-256-GCM, ChaCha20-Poly1305
- Public key crypto: RSA-2048+, ECDSA P-256+
- Hashing: SHA-256+
- Password storage: Argon2id, bcrypt with cost ≥12, or scrypt
Avoid:
- MD5
- SHA-1
- DES
- RC4
- ECB mode
- Custom encryption schemes
- Reused IVs/nonces
- Non-CSPRNG randomness for security-sensitive values
Rules:
- Use authenticated encryption for confidential data.
- Generate IVs/nonces using a CSPRNG.
- Never reuse nonces with the same key.
- Never store passwords with plain hashes.
- Fail closed.
- On unexpected errors, deny the operation unless there is a safe fallback.
- Return generic errors to users.
- Log detailed errors server-side only.
- Do not expose stack traces, internal paths, queries, schemas, tokens, or service topology to clients.
- Structured logs must not contain secrets or unnecessary PII.
- Rate-limit repeated authentication failures.
- Alert on suspicious spikes in auth failures, authorization failures, parsing failures, and unexpected 5xx errors.
Rule: Error paths are security paths.
When touching sensitive data:
- Identify whether the code handles PII, credentials, tokens, financial data, health data, customer data, or internal security data.
- Minimize collection and retention.
- Do not log sensitive data unless explicitly required and safely redacted.
- Encrypt sensitive data at rest and in transit.
- Avoid copying production data into local development or test environments.
- Use anonymized or synthetic test data where possible.
Rule: Sensitive data should have a clear owner, purpose, retention period, and access boundary.
When fixing or changing security-sensitive behavior:
- Add regression tests for the vulnerable or risky case.
- Test both allowed and denied paths.
- Test boundary cases, malformed input, and privilege failures.
- Ensure authorization tests cover cross-user, cross-tenant, and cross-org access.
- Add negative tests for injection, traversal, SSRF, unsafe redirects, and auth bypasses where relevant.
Rule: A security fix without a regression test is incomplete unless there is a documented reason.
Run this before opening a PR for significant code, infra, auth, data, or dependency changes.
[ ] Identified all entry points: HTTP, CLI, events, files, queues, webhooks, cron, etc.
[ ] Identified all trust boundaries crossed.
[ ] Identified sensitive data flows: PII, credentials, keys, customer data, security data, etc.
[ ] Validated inputs at each boundary.
[ ] Verified authentication and authorization for protected resources.
[ ] Confirmed authorization is enforced near the resource or invariant is documented.
[ ] Confirmed no secrets are present in code, config, logs, traces, or tests.
[ ] Confirmed least privilege for files, processes, DB users, cloud IAM, and tokens.
[ ] Checked injection risks: SQL, shell, template, LDAP, XPath, SSRF, deserialization, path traversal.
[ ] Reviewed new or changed dependencies.
[ ] Confirmed error paths fail closed and do not leak sensitive internals.
[ ] Added or updated security-relevant tests.
[ ] Documented important security assumptions inline.
## Extra tooling
When available and allowed by user run tooling for security verification before final push to upstream.
Hacktron.ai for PR scanning and pentest
For local tooling:
Python: bandit
General: semgrep
JavaScript/TypeScript: eslint-plugin-security
Go: gosec
Dependency Audit
Python: pip-audit
Node.js: npm audit
Rust: cargo audit
Containers/filesystems: trivy
Secret Scanning
gitleaks
trufflehog
Containers
trivy image
docker scout
If a tool reports a finding, either fix it or explicitly document why it is not applicable. Do not silently suppress security findings.