# Secure coding best practices: a checklist your team can use

> The secure coding practices that prevent most real vulnerabilities, from input validation to dependency updates, with a checklist for code review.

- URL: https://computese.com/best-practices-for-secure-coding/
- Author: Duong Quan Nguyen, CEO, Computese
- Published: 2024-07-21
- Updated: 2026-09-25
- Topics: Security, Web development

## In short
- Most vulnerabilities in custom software come from a short list of habits: trusting input, building queries from strings, missing permission checks, leaked secrets and unmaintained dependencies.
- Broken access control is A01 in the OWASP Top 10:2025, and cross-site scripting and SQL injection top the 2025 CWE Top 25: check authorization on every request and keep data apart from code.
- Use OWASP ASVS 5.0 as the testable standard, and NIST's Secure Software Development Framework to organize the process around it.
- Automate what reviewers stop noticing (static analysis, dependency, secret and container scanning on every pull request) and spend human review on design, access control and AI-generated code.

Most security incidents in custom software do not start with an exotic attack. They start with a small, familiar mistake: a query built from a string, a missing permission check, a key committed to a repository. Secure coding is the habit of not making those mistakes, and of catching them in review when someone does.

This guide covers the practices that prevent most real vulnerabilities, why each one matters, and a checklist you can use in code review. If you run a site rather than write its code, our [website security checklist](https://computese.com/essential-tips-to-secure-your-website/) is the better start; if you are new to programming, begin with our [tips for new coders](https://computese.com/essential-tips-for-new-coders/).

## Why secure coding is a habit, not a phase

Security added at the end of a project is expensive. By then the data model, the authentication flow and the dependencies are fixed, and a design flaw means rework. The cheaper path is to [make secure choices the default](https://www.cisa.gov/securebydesign) while the code is being written, and to let automation check the rest on every change.

That does not require every developer to be a security specialist. It requires a short list of rules the whole team follows, a review process that looks for the common failures, and tooling that runs without anyone having to remember it.

## The standards worth building on

You do not have to invent the rules. Four public references cover most of what a team needs, and each does a different job:

| Reference                                                                       | What it is                                                                         | Use it for                                                     |
| ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| [OWASP Top 10:2025](https://top10.owasp.org/2025)                               | The ten most critical web application risk categories                              | Awareness and training; deciding what to review first          |
| [2025 CWE Top 25](https://cwe.mitre.org/top25/archive/2025/2025_cwe_top25.html) | MITRE's ranking of the most dangerous weakness types, from real vulnerability data | Prioritizing checks and static analysis rules                  |
| [OWASP ASVS 5.0](https://asvs.dev/)                                             | Testable security requirements for web apps and services, released May 2025        | Requirements, test cases and the definition of done            |
| [NIST SSDF (SP 800-218)](https://csrc.nist.gov/pubs/sp/800/218/final)           | A framework of secure development practices                                        | Organizing the process: training, tooling, review and response |

The 2025 lists agree on where the damage comes from. [Broken access control is A01](https://top10.owasp.org/2025/A01_2025-Broken_Access_Control/) in the OWASP Top 10:2025, followed by security misconfiguration and a new category for software supply chain failures. The top of the 2025 CWE Top 25 is cross-site scripting (CWE-79), SQL injection (CWE-89), cross-site request forgery (CWE-352) and missing authorization (CWE-862). The practices below map onto those lists.

## Handle input and output safely

Injection flaws and cross-site scripting both come from the same root cause: data from outside the system is treated as code. The fix is to keep data and code apart at every boundary.

### Validate input at the boundary

Check every input where it enters the system: form fields, query strings, headers, file uploads, webhooks and messages from other services. Validate on the server, even when the browser already checked, because client-side checks are a convenience for users, not a control.

- Prefer allowlists (what is permitted) over blocklists (what is forbidden).
- Check type, length, format and range, and reject anything that does not match.
- Parse structured input with a schema library instead of hand-written checks.

### Use parameterized queries

Never build a database query by joining strings. [Pass user input as a parameter](https://cheatsheetseries.owasp.org/cheatsheets/Query_Parameterization_Cheat_Sheet.html), so the database treats it as a value and never as part of the command.

```ts
// Vulnerable: the input becomes part of the SQL text
const orders = await db.query(
  `SELECT * FROM orders WHERE customer_id = '${customerId}'`,
);

// Safe: the input is sent as a parameter, never parsed as SQL
const orders = await db.query("SELECT * FROM orders WHERE customer_id = $1", [
  customerId,
]);
```

The same rule applies to shell commands, LDAP queries and template engines. If an API accepts a single string that mixes command and data, look for the version that takes them separately.

### Encode output for where it lands

Data that is safe in a database can be dangerous in a web page. Encode output for its context: HTML body, HTML attribute, URL or JavaScript each need different escaping. Modern frameworks such as React escape by default, so the risk concentrates in the places that bypass it, like raw HTML rendering. Treat every one of those as a review item, and add [a Content Security Policy](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html) as a second layer.

## Get identity and access right

Broken access control is A01 in the OWASP Top 10:2025, as it was in 2021. It is rarely a clever exploit; usually a request simply reaches data it should not.

### Use proven authentication, never your own

Use a maintained identity provider or framework for sign-in, password resets and multi-factor authentication, and offer passkeys where your platform supports them. If you store passwords, hash them with an algorithm designed for passwords, never with a general-purpose hash such as SHA-256. [OWASP's Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) puts Argon2id first, with at least 19 MiB of memory, two iterations and one degree of parallelism; scrypt next; bcrypt with a work factor of 10 or more for legacy systems; and PBKDF2 with HMAC-SHA-256 and 600,000 or more iterations where FIPS-140 compliance is required.

### Check authorization on every request

Check permissions on the server for every request, not only when a page loads. The classic failure is an endpoint like `/invoices/1042` that returns any invoice to any signed-in user who changes the number. Deny by default, check that the user may act on _this_ record, and write tests for the refusal as well as the success. In an API this flaw is called broken object level authorization, and our guide to [enterprise API development](https://computese.com/the-future-of-enterprise-api-development/) covers it with the rest of the OWASP API Security Top 10.

### Protect sessions and cookies

Set session cookies with `HttpOnly`, `Secure` and `SameSite`, expire sessions after inactivity, and [issue a new session identifier after sign-in](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html). Protect state-changing requests against cross-site request forgery, which most frameworks handle once it is switched on.

## Protect secrets and data

### Keep secrets out of the codebase

API keys, database passwords and tokens belong in environment variables or [a secrets manager](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html), never in source code or in files committed to the repository. Assume anything committed is permanent: deleting it in a later commit leaves it in the history. If a secret leaks, rotate it first and clean up second.

### Use vetted cryptography

Use the encryption your platform and well-known libraries provide, with current defaults: TLS 1.2 or later in transit, and managed encryption for data at rest. Do not design your own algorithms or protocols, and do not store encryption keys next to the data they protect.

### Log events, not sensitive data

Record security-relevant events: sign-ins, failed sign-ins, permission denials and changes to roles or settings. Keep passwords, tokens, full card numbers and personal data out of the logs, because logs are copied to more places, and read by more people, than the database.

## Fail safely

When something goes wrong, the system should fail closed: deny the action rather than allow it. The OWASP Top 10:2025 gives this its own category, A10, mishandling of exceptional conditions: an unhandled error in the middle of a payment or a permission check can leave the system in a state nobody designed.

- Catch errors where you can act on them, and roll back partial changes inside a transaction.
- Treat timeouts and unexpected responses from other services as failures, not as success.
- Show users a plain message and a reference number, and keep stack traces, SQL errors and internal paths in your logs. Detailed error pages in production tell an attacker exactly how the application is built.

## Keep dependencies and configuration under control

### Treat dependencies as code you ship

Most of an application's code comes from third-party packages, and their vulnerabilities become yours. The OWASP Top 10:2025 made this its own category, [A03, software supply chain failures](https://top10.owasp.org/2025/A03_2025-Software_Supply_Chain_Failures/), covering compromised packages and build pipelines as well as outdated components.

![Packages travel from a registry shelf into a stack of blocks that forms an application. One block is orange, a component with a known vulnerability, and a sheet beside the stack lists every block.](https://computese.com/images/blog/best-practices-for-secure-coding/supply.113aa8fbbf-1536.webp)

*Most of what you ship, you did not write. Know every component, where it came from and which version is inside.*

- Commit a lockfile, pin versions and remove packages you no longer use.
- Update on a regular schedule instead of all at once when something breaks, and let a bot open the pull requests.
- Check new packages before adding them: who maintains them, how active they are, what they pull in, and whether the name is a near-miss of a popular package (typosquatting).
- Generate a software bill of materials (SBOM) at build time, so that when a vulnerability is announced you can tell in minutes which applications contain the affected version.
- Protect the pipeline itself: least-privilege tokens in CI, protected branches, and signed or provenance-checked build artifacts.

### Ship secure defaults

Turn on the protections that cost nothing once configured: HTTPS everywhere, security headers, and least privilege for database users and service accounts. Disable debug modes, sample pages and default credentials before anything reaches production.

## Make it part of the workflow

Rules only work if they are checked. Code review catches design problems that tools miss, and automated checks catch the repetitive ones that reviewers stop noticing. Run both on every change.

![A code change moves through a gear of automated checks, then between two laptops that review it. One orange line in the change is circled: the problem the tools passed and the reviewers caught.](https://computese.com/images/blog/best-practices-for-secure-coding/review.29f97a3e07-1536.webp)

*Every change passes the automated checks, then a second person. Reviewers catch the design and access problems that tools miss.*

| Check                      | What it catches                                                     | When it runs                        |
| -------------------------- | ------------------------------------------------------------------- | ----------------------------------- |
| Static analysis (SAST)     | Injection patterns, unsafe APIs and missing checks in your own code | Every pull request                  |
| Dependency scanning        | Known vulnerabilities in third-party packages                       | Every build, and on a schedule      |
| Secret scanning            | Keys and tokens committed by mistake                                | Every push                          |
| Dynamic testing (DAST)     | Flaws and misconfigurations visible in the running application      | Against staging, before release     |
| Container and IaC scanning | Vulnerable base images and insecure cloud or Kubernetes settings    | Every build of an image or template |

If you do not have these checks in place yet, our [security testing service](https://computese.com/services/security-testing/) sets them up and reads the results with you, so findings arrive ranked and with a fix, not as a raw report.

## Review AI-generated code like any other contribution

Coding assistants now write a large share of new code, and they write it with confidence whether or not it is right. Treat their output like a pull request from a capable new contributor who has never seen your threat model. What the studies say about AI assistants and code security, and how teams adopt them, is in our guide to [the future role of software engineers](https://computese.com/the-future-role-of-software-engineers/).

- **Check every import.** In [a study presented at USENIX Security 2025](https://arxiv.org/abs/2406.10279), code-generating models recommended packages that do not exist, at least 5.2% of the time for commercial models and 21.7% for open-source ones. Attackers can register those names, so a hallucinated dependency can become a malicious one ("slopsquatting").
- **Look for the old mistakes.** Generated code reproduces patterns from its training data, including string-built SQL, disabled certificate checks and missing authorization.
- **Keep secrets out of prompts.** Do not paste keys, customer data or proprietary code into tools your organization has not approved for it.
- **Let the same gates apply.** AI-written code goes through the same static analysis, dependency and secret scanning, tests and human review as everything else.

## A checklist for your next code review

1. Is every new input validated on the server, with an allowlist?
2. Do queries and commands take user data as parameters, never as concatenated strings?
3. Is output encoded for its context, and does anything bypass the framework's escaping?
4. Does every new endpoint check that this user may act on this specific record?
5. Are secrets read from the environment, with none added to the repository?
6. Do errors fail closed and keep internal details out of responses?
7. Are security events logged without sensitive data?
8. Are new dependencies necessary, maintained, pinned and real (not a hallucinated or look-alike name)?
9. Does the change handle errors and timeouts by failing closed?

## Where to start with an existing codebase

You do not need to fix everything at once. Start with the checks that run themselves: dependency and secret scanning take an afternoon to switch on and immediately show your largest exposures. Then review the areas attackers reach first, which are authentication, authorization and anything that accepts file uploads or builds queries. Fix what you find, add a test for each fix, and make the checklist above part of every review from then on. Pick the ASVS level that matches the data you hold, and measure the application against it once a year, or after a major change.

## Key terms
- **Secure coding**: Writing software so that ordinary defects do not become exploitable vulnerabilities, and checking that before release.
- **Injection**: A flaw where untrusted data is interpreted as part of a command or query, as in SQL injection, OS command injection or cross-site scripting.
- **Broken access control**: A request can read or change data, or run functions, that the user should not be allowed to. A01 in the OWASP Top 10:2025.
- **OWASP ASVS**: The Application Security Verification Standard: testable security requirements for web applications and services. Version 5.0 was released in May 2025.
- **CWE Top 25**: MITRE's yearly ranking of the most dangerous software weakness types, built from real vulnerability data.
- **SAST, DAST and SCA**: Static analysis of your source code, dynamic testing of the running application, and software composition analysis of third-party dependencies.
- **SBOM**: A software bill of materials: the list of components and versions inside an application, used to find where a newly disclosed vulnerability applies.
- **Argon2id**: A memory-hard password hashing algorithm, the first choice in OWASP's Password Storage Cheat Sheet.

## Common questions

### What is secure coding?

Secure coding is the set of habits that keep ordinary defects from becoming exploitable vulnerabilities. It covers how code handles input, identity, secrets, errors and dependencies, and how the team checks all of that before release.

### Which secure coding standard should we follow?

For web applications, the OWASP Application Security Verification Standard (ASVS) is the most practical starting point, because it is written as testable requirements. The OWASP Top 10 and the CWE Top 25 are useful for awareness and prioritization rather than as checklists, and NIST's SSDF (SP 800-218) describes the development process around them.

### How often should we scan our code?

Run static analysis, dependency scanning and secret scanning on every pull request, so problems are caught while the change is still small. Re-scan dependencies on a schedule as well, because new vulnerabilities are published for code you have not touched.

### Is code written by AI assistants secure?

Treat it like code from a new contributor: review it, test it and scan it. A 2025 USENIX Security study found that code-generating models recommended packages that do not exist, at least 5.2% of the time for commercial models and 21.7% for open-source ones, and attackers register such names.

### What is the most common secure coding mistake?

Missing or inconsistent authorization checks. Broken access control is A01 in the OWASP Top 10:2025, and missing authorization (CWE-862) ranks fourth in the 2025 CWE Top 25.

## Sources
1. [OWASP Top 10:2025](https://top10.owasp.org/2025), OWASP Foundation
2. [A01:2025 Broken Access Control](https://top10.owasp.org/2025/A01_2025-Broken_Access_Control/), OWASP Foundation
3. [A03:2025 Software Supply Chain Failures](https://top10.owasp.org/2025/A03_2025-Software_Supply_Chain_Failures/), OWASP Foundation
4. [Application Security Verification Standard (ASVS)](https://asvs.dev/), OWASP Foundation
5. [2025 CWE Top 25 Most Dangerous Software Weaknesses](https://cwe.mitre.org/top25/archive/2025/2025_cwe_top25.html), MITRE
6. [SP 800-218: Secure Software Development Framework (SSDF) Version 1.1](https://csrc.nist.gov/pubs/sp/800/218/final), NIST
7. [Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html), OWASP Cheat Sheet Series
8. [Query Parameterization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Query_Parameterization_Cheat_Sheet.html), OWASP Cheat Sheet Series
9. [Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html), OWASP Cheat Sheet Series
10. [Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html), OWASP Cheat Sheet Series
11. [Content Security Policy Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html), OWASP Cheat Sheet Series
12. [We Have a Package for You! A Comprehensive Analysis of Package Hallucinations by Code Generating LLMs](https://arxiv.org/abs/2406.10279), USENIX Security 2025 (arXiv)
13. [Secure by Design](https://www.cisa.gov/securebydesign), CISA
