A secure SDLC policy says that code must be written securely; a secure coding standard says exactly what that means, in rules a developer can follow and a reviewer or scanner can check. This template gives [Organisation] a language-neutral standard with numbered rules for authentication, authorisation, secrets, input and output handling, errors and logging, and dependencies, each with a conformance level and a verification method. Language-specific annexes then add the idioms for each stack. It is for application security leads, engineering managers and security champions who need a standard that auditors can trace and developers will actually use. The background on why each rule matters is in the Secure Coding Guide; the policy that requires a standard is in the Secure SDLC Policy Template.
How to use this template
- Keep the rule IDs stable: scanners, review checklists, training and exceptions will reference them, so retire IDs rather than renumbering.
- Set the conformance levels: "Must" rules block a merge when broken; "Should" rules are expected unless a reason is recorded in the pull request. Adjust the split to your risk appetite, but keep every Must rule checkable.
- Fill the placeholders: [square brackets] mark choices [Organisation] makes, such as the approved secrets manager, password hashing function or logging library.
- Add language annexes, do not fork the core: section 11 is where Java, Go, Python or TypeScript specifics go, so the core rules stay the same across teams.
- Map rules to tools: fill the "Verified by" column with the actual static analysis rule, test or review item, so every Must rule has an automated or recorded check.
1. Purpose
This standard defines the minimum secure coding rules for software developed by or for [Organisation]. It implements the secure development requirements of the [Secure SDLC Policy] and supports [NIST SP 800-218 (SSDF) practice PW.5, other frameworks [Organisation] follows, and customer contractual requirements].
2. Scope
- All application, service, infrastructure-as-code and script code in repositories owned by [Organisation], including code produced by AI coding assistants and agents.
- Code delivered by contractors and suppliers under [Organisation] contracts.
- Out of scope: [prototypes in isolated sandboxes with no real data or credentials, as defined in the Vibe Coding Policy]. See the Vibe Coding Policy Template.
3. Roles and responsibilities
| Role | Responsibility |
|---|---|
| [Head of Application Security] | Owns this standard, approves changes and deviations for Must rules |
| Engineering managers | Ensure teams are trained and that pipelines enforce the checks |
| Developers (and anyone merging AI-generated code) | Follow the rules; the person who merges code is accountable for it, whoever or whatever wrote it |
| Reviewers and security champions | Check Should rules and judgement-based Must rules in review |
| Platform team | Maintains scanner configuration mapped to rule IDs |
4. Rule format and conformance
Each rule has an ID (area prefix and number), a statement, a level (Must or Should) and a verification method: SAST (static analysis rule), SCAN (secret or dependency scanning), TEST (automated test), or REVIEW (manual review item). Rules reference OWASP ASVS 5.0 requirements so the standard can be traced to a verification level.
5. Authentication and sessions (AUTH)
| ID | Rule | Level | Verified by | ASVS 5.0 |
|---|---|---|---|---|
| AUTH-01 | Use [Organisation's identity provider] for user login; do not build custom password authentication without [Head of AppSec] approval | Must | REVIEW | Not mapped |
| AUTH-02 | Every endpoint that changes data or returns non-public data requires authentication, declared through the framework's central mechanism, not per handler | Must | SAST, TEST | V6.3.4 |
| AUTH-03 | Where passwords are stored locally, hash them only with [approved password hashing function and parameters] | Must | SAST | V11.4.2 |
| AUTH-04 | Validate token signature, algorithm allowlist, issuer, audience and expiry before using any claim | Must | TEST | V9.1.1, V9.1.2, V9.2.1, V9.2.3 |
| AUTH-05 | Issue a new session identifier at login and invalidate it server-side at logout | Must | TEST | V7.2.4, V7.4.1 |
| AUTH-06 | Login and reset responses do not reveal whether an account exists | Should | TEST | V6.3.8 |
| AUTH-07 | No default, test or backdoor accounts or bypass flags in production builds | Must | SAST, REVIEW | V6.3.2 |
6. Authorisation (AUTHZ)
| ID | Rule | Level | Verified by | ASVS 5.0 |
|---|---|---|---|---|
| AUTHZ-01 | Deny by default: every route or function declares the permission it requires | Must | SAST, TEST | V8.2.1 |
| AUTHZ-02 | Check object ownership or entitlement for every identifier taken from a request | Must | TEST, REVIEW | V8.2.2 |
| AUTHZ-03 | Enforce authorisation on the server; client-side checks are for usability only | Must | REVIEW | V8.3.1 |
| AUTHZ-04 | Bind request data to explicit allowlists of fields per action (no mass assignment) | Must | SAST | V15.3.3 |
| AUTHZ-05 | Decisions for delegated calls use the originating user's permissions | Should | REVIEW | V8.3.3 |
| AUTHZ-06 | Use the shared authorisation library [name]; do not hand-write role checks | Should | SAST | Not mapped |
See the Broken Access Control Prevention Guide and the Authorisation Models Guide.
7. Secrets and cryptography (SEC)
| ID | Rule | Level | Verified by | ASVS 5.0 |
|---|---|---|---|---|
| SEC-01 | No secrets in source code, tests, configuration files, container images, build arguments or comments | Must | SCAN (pre-commit and CI) | V13.3.1 |
| SEC-02 | Read secrets at runtime from [approved secrets manager]; prefer mounted files or in-memory retrieval over environment variables | Must | REVIEW | V13.3.1 |
| SEC-03 | Each workload identity can read only the secrets it needs; production and non-production secrets are separate | Must | REVIEW | V13.3.2 |
| SEC-04 | Prefer short-lived, dynamically issued credentials (workload identity, OAuth client credentials with short tokens) over static keys | Should | REVIEW | V13.2.1 |
| SEC-05 | Never log, print or return secrets or tokens; mask them in error output | Must | SAST, REVIEW | V16.5.1 |
| SEC-06 | Use [approved crypto library] and approved algorithms only; no custom cryptography | Must | SAST | V11.4.1 |
| SEC-07 | Generate tokens, identifiers and codes with a cryptographically secure random generator | Must | SAST | V11.5.1 |
| SEC-08 | Never disable TLS certificate validation, including in test code that can reach production | Must | SAST | V12.3.2 |
A secret committed to a repository is treated as exposed and rotated, even if the commit is reverted. See the Secrets Management Guide and the Git Secret Scanning Guide.
8. Input and output handling (IO)
| ID | Rule | Level | Verified by | ASVS 5.0 |
|---|---|---|---|---|
| IO-01 | Validate all input server-side against an allowlist of type, length, range and format | Must | REVIEW, TEST | V2.2.1, V2.2.2 |
| IO-02 | Use parameterised queries or the ORM's safe API; never build queries by string concatenation | Must | SAST | V1.2.4 |
| IO-03 | Do not invoke a shell with input; use APIs that take arguments as a list | Must | SAST | V1.2.5 |
| IO-04 | Encode output for its context using the framework's auto-escaping; document any place it is switched off | Must | SAST, REVIEW | V1.2.1 |
| IO-05 | Do not deserialise untrusted data into arbitrary types; disable external entities in XML parsers | Must | SAST | V1.5.1, V1.5.2 |
| IO-06 | Server-side requests to URLs influenced by input use a destination allowlist and do not follow redirects by default | Must | REVIEW, TEST | V13.2.4, V15.3.2 |
| IO-07 | Uploaded files are checked for type, size and archive limits and stored outside the web root | Must | TEST | V5.2.1, V5.2.2, V5.2.3 |
| IO-08 | Return only the fields the caller needs, not whole data objects | Should | REVIEW | V15.3.1 |
See the Input Validation and Output Encoding Guide and the SSRF Prevention Guide.
9. Errors and logging (LOG)
| ID | Rule | Level | Verified by | ASVS 5.0 |
|---|---|---|---|---|
| LOG-01 | Return generic error messages to callers; keep detail in server logs | Must | TEST | V16.5.1 |
| LOG-02 | Fail closed: an exception in an authorisation, payment or approval step stops the action | Must | REVIEW, TEST | V16.5.3 |
| LOG-03 | Log authentication outcomes and authorisation failures through [logging library] with user, time and source | Must | TEST | V16.3.1, V16.3.2 |
| LOG-04 | Do not log secrets, session tokens or full payment or health data | Must | SAST, REVIEW | V16.2.5 |
| LOG-05 | Debug modes and verbose errors are off in production configuration | Must | TEST | V13.4.2 |
See the Secure Error Handling and Logging Guide.
10. Dependencies, configuration and non-human identities (DEP)
| ID | Rule | Level | Verified by | ASVS 5.0 |
|---|---|---|---|---|
| DEP-01 | Install packages only from [approved registry or proxy]; verify that AI-suggested packages exist and are the intended ones | Must | SCAN | V15.2.4 |
| DEP-02 | Keep a software bill of materials for every deployable artefact | Must | SCAN | V15.1.2 |
| DEP-03 | Fix vulnerable components within the remediation windows in [Vulnerability Management Standard] | Must | SCAN | V15.1.1, V15.2.1 |
| DEP-04 | Production builds exclude test code, sample data and source control metadata | Must | TEST | V13.4.1, V15.2.3 |
| DEP-05 | Every service account, API key or workload identity the code introduces has a named owner, a purpose and least privilege scopes, recorded in [inventory] | Must | REVIEW | V13.3.2 |
See the Service Account Security Guide.
11. Language annexes
Each annex lists, for one language or framework: the approved libraries for the placeholders above, the safe and banned APIs, and the scanner rules mapped to each core rule ID. Start from the relevant NHI Mgmt Group language guide:
- C and C++: memory safety rules in addition to the core. See the C and C++ Secure Coding Guide.
- Go: see the Go Secure Coding Guide.
- Java: see the Oracle Java Secure Coding Guidelines Guide.
- Mobile: see the Kotlin and Android Secure Coding Guide and the Swift and iOS Secure Coding Guide.
- [Other languages in use]: [annex owner, date].
12. Deviations
- A Must rule may be broken only with a recorded deviation: rule ID, location, reason, compensating control, approver ([Head of AppSec]) and expiry date no later than [12 months].
- A Should rule may be departed from with a reason recorded in the pull request.
- Deviations are reviewed [quarterly]; expired deviations block the next release of the affected component. See the Security Exceptions and Risk Acceptance Guide.
13. Review and approval
This standard is reviewed at least [annually], after any vulnerability class reaches production, and when OWASP ASVS or the CWE Top 25 is revised. Owner: [Head of Application Security]. Approved by: [CISO], [date]. Version: [1.0].
Implementation guidance
- Map before you mandate: for each Must rule, confirm a scanner rule, test or review item exists in every language you use. Rules with no check become Should until one does.
- Run in report mode first: enable the scanner rules in non-blocking mode for [four weeks], measure findings per rule and fix false positives.
- Block on a small core: start with SEC-01, IO-02, IO-03 and AUTHZ-01 as blocking gates, then add rules as the false positive rate falls.
- Train on the standard, not on generic content: use the rule IDs in onboarding and in review comments. See the Developer Security Training Programme Guide.
- Roll back safely: if a blocking rule stalls delivery, return it to report mode with an owner and date, rather than deleting it.
Choosing the level of prescription
| Situation | Approach |
|---|---|
| Small team, one or two languages | Core rules plus one annex; reviewers check REVIEW items with the pull request template |
| Many teams and stacks | Core rules owned centrally, annexes owned by language guilds, scanner configuration shared as code |
| Regulated or high-assurance software | Map every rule to ASVS Level 2 or 3, keep evidence of each check per release |
| Heavy use of AI coding tools | Add DEP-01 and SEC-01 as blocking gates first; generated code follows the same rules |
Metrics
- Share of Must rules with an automated check in each language.
- Findings per rule ID per thousand lines changed, by team.
- Open deviations, and deviations past expiry.
- Production vulnerabilities traced to a rule that existed but was not enforced.
Framework mapping
| Framework | Reference |
|---|---|
| NIST SP 800-218 (SSDF 1.1) | PW.5 Create source code by adhering to secure coding practices |
| NIST SP 800-53 Rev 5 | SA-15 Development Process, Standards, and Tools; SA-11 Developer Testing and Evaluation; SI-10 Information Input Validation |
| NIST CSF 2.0 | PR.PS-06 |
| OWASP Top 10 Proactive Controls 2024 | C1 access control, C2 cryptography, C3 input and exceptions, C6 components, C7 digital identities, C9 logging, C10 SSRF |
Common failure patterns
- A standard nobody can check: rules phrased as advice ("be careful with input") that no scanner or reviewer can test.
- Copying a language standard wholesale: hundreds of rules, most irrelevant, so developers ignore the lot.
- No owner for annexes: the core is approved but the language-specific mapping never gets written.
- Permanent deviations: exceptions with no expiry become the real standard.
Standards and references
- OWASP: Application Security Verification Standard 5.0
- OWASP: Top 10 Proactive Controls 2024
- OWASP: Secrets Management Cheat Sheet
- NIST: SP 800-218 Secure Software Development Framework (SSDF) Version 1.1
- Carnegie Mellon SEI: CERT Coding Standards
- MITRE: 2025 CWE Top 25 Most Dangerous Software Weaknesses
Related NHI Mgmt Group resources: Secure Coding Guide · Secure SDLC Policy Template · Secure Code Review Guide · OWASP ASVS Guide