Skip to content
OpenAgentsbeta
text
1# Secure Coding Rules
2
3A CLAUDE.md/AGENTS.md-style rules set. Load this alongside a project's own rules; it
4constrains how code is written, not what feature to build. These rules apply to all
5code the agent writes or edits, not only code explicitly flagged as "security-sensitive"
6— the majority of real vulnerabilities show up in ordinary CRUD code, not crypto code.
7
8## Secrets
9
10- Never hardcode API keys, passwords, tokens, connection strings, or private keys in
11 source, tests, fixtures, or comments — including "just for now" or "I'll remove it
12 later." Use environment variables or a secrets manager.
13- Never print, log, or echo a secret's value, even for debugging. Log that a secret was
14 loaded/missing, not its contents.
15- Never commit `.env` files with real values. Check `.gitignore` covers them before
16 creating one; if it doesn't, add it before writing the file.
17- When a secret is genuinely needed in a prompt/example, use an obvious placeholder
18 (`sk-...REDACTED...`, `<YOUR_API_KEY>`), never a real-looking fake that could be
19 mistaken for a leaked credential.
20- Rotate-on-suspicion: if a secret is found committed to history, treat it as
21 compromised — flag it for rotation, don't just delete the line in a new commit
22 (history still has it).
23
24## Input validation
25
26- Validate all external input at the boundary: HTTP request bodies/params/headers,
27 query strings, file uploads, CLI arguments, environment variables, webhook payloads,
28 and data read from a queue. "External" means anything not constructed by this
29 process in this request.
30- Validate shape *and* semantics: a string field being present isn't enough — check
31 length bounds, allowed character sets/formats, and business-rule bounds (e.g.
32 quantity > 0).
33- Prefer allow-lists over deny-lists (enumerate what's valid, don't try to enumerate
34 every invalid thing).
35- Never trust a client-supplied ID as sufficient authorization to act on that resource
36 — validation confirms shape, not permission (see Authorization below).
37- Reject invalid input with a clear error; don't silently coerce/truncate it into
38 something "close enough."
39
40## Injection prevention
41
42- SQL/NoSQL: always use parameterized queries or an ORM's query builder. Never build a
43 query by concatenating/interpolating untrusted input into a query string.
44- Shell commands: avoid building commands from untrusted input at all where possible;
45 when unavoidable, use an API that passes arguments as an array (not a shell string)
46 and never pass untrusted input through `sh -c`/`shell: true`.
47- Deserialization: don't deserialize untrusted data with formats/libraries that can
48 execute code (e.g. Python `pickle`, unsafe YAML loaders) — use safe/restricted
49 loaders for untrusted input.
50- Template rendering: use the templating engine's auto-escaping; never mark untrusted
51 input as "safe"/raw HTML without a specific, reviewed reason.
52
53## Authorization & authentication
54
55- Every new or modified endpoint, mutation, or background job that acts on a specific
56 resource must check that the *current* actor is allowed to act on *that specific*
57 resource — not just that they're authenticated. Watch for IDOR: a client-supplied ID
58 is not proof of ownership.
59- Enforce authorization on the server/backend, never rely on a client (UI hiding a
60 button, a mobile app not showing a menu item) as the actual control.
61- Default to deny: new routes/fields start unauthorized-by-default and are opened up
62 explicitly, not the reverse.
63- Session tokens: use secure, httpOnly, sameSite cookies for web sessions where
64 applicable; never store auth tokens in localStorage if httpOnly cookies are an
65 option, since localStorage is readable by any script (XSS blast radius).
66- Passwords: hash with a modern algorithm (bcrypt/scrypt/argon2) with a proper work
67 factor. Never MD5/SHA1/SHA256 alone (no salt/stretch) for password storage.
68
69## Dependency hygiene
70
71- Before adding a new dependency: check it's actively maintained (recent releases),
72 reasonably popular/widely used, and has no known critical CVEs for the version being
73 added.
74- Pin versions (exact or narrow range) in the lockfile; don't introduce a dependency
75 with an unbounded version range.
76- Prefer the standard library or an existing dependency already in the project over
77 adding a new one for trivial functionality.
78- When updating a dependency across a major version, actually read the changelog for
79 breaking/security-relevant changes rather than bumping blindly.
80
81## Logging & PII
82
83- Never log full credentials, tokens, session IDs, or secrets — not even at debug
84 level.
85- Treat as PII and avoid logging in plaintext unless there's a specific, reviewed need:
86 full names, email addresses, phone numbers, physical addresses, government IDs,
87 precise geolocation, health/financial data. Mask or omit by default (e.g. log a user
88 ID, not their email).
89- Structured logs should have a defined field allow-list for what's safe to include;
90 don't `console.log`/`print` an entire request/response object that may contain
91 sensitive fields.
92- Error messages returned to end users should not leak internal details (stack traces,
93 file paths, SQL, internal hostnames) — log the detail internally, return a generic
94 message externally.
95
96## When in doubt
97
98If a change touches auth, payments, PII, or crypto and the right approach isn't
99obvious from these rules, say so explicitly and ask rather than guessing — these are
100exactly the categories where a quiet wrong guess becomes an incident. See
101`checklists/owasp-quick.md` for a fast pre-ship pass over the OWASP Top 10 categories.
102

Keyboard shortcuts

Focus search
/
Go to Explore
ge
Go to Home
gh
Go to Tags
gt
Go to Collections
gc
Show this help
?
Close suggestions or this dialog
Esc