Add a security checklist to your repository
Secure coding guidelines requires every repository to keep its own stack-specific checklist. This page is how you create one, and — the part people skip — how you make the assistants actually read it.
Several repositories already have one: rekkari, inbox, my-vehicles, nettix-web,
nettix-api, nettix-www, auth-api and maksuportaali. Copy the closest of those to
your stack before starting from the template below.
Where the file goes
Section titled “Where the file goes”.ai/security-checklist.md. That path is deliberately tool-neutral: no assistant owns
it, so the same file serves Claude Code, Cursor and whatever the next tool is, and it
sits next to the other .ai/ documents the repositories already keep.
What each file around it is for:
| File | Who reads it | What belongs in it |
|---|---|---|
.ai/security-checklist.md |
every assistant, and people | the checklist itself — the canonical copy |
AGENTS.md |
Cursor natively, and most other agents | the hard rules, plus a pointer to .ai/ |
CLAUDE.md |
Claude Code only | an @AGENTS.md import, plus Claude-specific notes |
.claude/rules/security.md |
Claude Code, when it reads a matching file | a short digest, scoped with paths: |
.cursor/rules/security.mdc |
Cursor, when its globs match | a short digest, referencing the canonical file |
Keep the checklist in one place and let the rest point at it. Two copies of a security rule means one of them is wrong within a month.
Wire it up so it actually loads
Section titled “Wire it up so it actually loads”Claude Code reads CLAUDE.md, not AGENTS.md, and a Markdown link is not an
import. [AGENTS.md](AGENTS.md) in a sentence loads nothing; @AGENTS.md on its own
line loads the file at session start.
@AGENTS.md
## Claude Code
- Before changing an API boundary, read `.ai/security-checklist.md`.A path inside backticks stays literal, which is how you mention a file without pulling it into context.
For rules that should only load when the relevant code is open, add
.claude/rules/security.md and scope it:
---paths: - "src/**/*.php" - "web/src/**/*.{ts,tsx}"---
Authorization is checked per resource, not per role. Input is validated before use.Full checklist: `.ai/security-checklist.md`.For Cursor, add .cursor/rules/security.mdc — a plain .md file in that directory is
ignored, because the frontmatter is what Cursor keys on:
---description: Security requirements for API boundaries and user inputglobs: ["src/**/*.php", "web/src/**/*.{ts,tsx}"]alwaysApply: false---
Follow @.ai/security-checklist.md for anything touching an API boundary, user input,payments or PII.Cursor also reads AGENTS.md from the root and from subdirectories, so a repository
with AGENTS.md plus the @AGENTS.md import in CLAUDE.md already covers both tools
without a third copy of the rules.
Check that it worked: start a Claude Code session in the repository and run /context.
The files listed under Memory files are the ones that actually loaded. If
CLAUDE.md is missing there, nothing you wrote in it is reaching the agent.
The template
Section titled “The template”Start from this and replace every bracketed part with what your stack actually does. The section names match Secure coding guidelines so a reviewer can move between the two.
# Security checklist — [repository]
Parent: https://docs.ajomark.dev/reference/secure-coding-guidelines/That page states the requirements. This file says how they are met here, and wherethis repository deviates.
## Quick reference (for PRs and plans)
- [ ] Authorization checked per resource, not only per role — [where that lives here]- [ ] All request input validated before business logic — [validator or type layer]- [ ] Queries parameterized — [ORM or query builder, and the forbidden pattern]- [ ] Output escaped for its context — [template engine, autoescape status]- [ ] Secrets from [AWS Secrets Manager / Parameter Store], never a committed file- [ ] No PII in logs — [the fields that count as PII here]- [ ] Uploads validated by content and size-limited — [handler]- [ ] External lookups rate-limited and attributable — [which services, which limits]- [ ] Security events logged — [logger, and how they are distinguishable]- [ ] Errors return no internal detail — [error handler]- [ ] Third-party actions pinned by SHA; internal reusable workflows at `@main` — [any workflow this repository must pin, and why]- [ ] Workflow callers forward named secrets, not `secrets: inherit` — [the exceptions here, and why]- [ ] No user-controlled `${{ github.event.* }}` in `run:` blocks — passed through `env:`
## Stack-specific patterns
### [Area, e.g. authorization]
Correct:
```[language][the pattern this repository uses]```
Wrong:
```[language][the mistake that actually happens here]```
## Deviations
| Requirement | Why not met | Compensating control | Approved by | Review date ||---|---|---|---|---|| [rule from the parent page] | [reason] | [what covers it meanwhile] | [owner] | [ISO date] |
A deviation covering a Critical or High finding also goes in the unit's continuity riskassessment, with the engineering manager notified. This table alone does not reach theunit's risk review.
## Enforcement
- Pre-commit: [what the hook blocks on]- CI: [what `security-scan` runs, and whether it gates a merge]- Action pinning: scored by Scorecard, gated by nothing — a review item- Review: everything the three above cannot checkKeep it short enough that it gets read. Rules a tool already enforces belong in the tool, not in prose — the checklist guides an agent and a reviewer, and gates nothing on its own.
Related
Section titled “Related”- Secure coding guidelines — the requirements this checklist implements
- How supply-chain security works — what gates a merge, which an instruction file never does
- Context for agents — which layer each fact belongs in,
across
AGENTS.md,CLAUDE.md,.ai/and skills - Install the AJOMARK Claude skills — the shared skills that write our tickets, specs and ADRs