The majority of application breaches exploit vulnerabilities that were present in the codebase for months or years before they were discovered. SQL injection, hardcoded credentials, insecure dependencies, and missing input validation — these aren't sophisticated attack vectors. They're preventable coding mistakes that slipped through because security wasn't part of the development process. The question isn't whether your code has vulnerabilities. It's whether you find them first.
This guide covers the code security practices that eliminate the most common vulnerability classes, the tooling that makes them feasible at development speed, and how to build security into your CI/CD pipeline without slowing your team down.
The OWASP Top 10: Where Most Breaches Actually Come From
The OWASP Top 10 is the definitive list of the most critical web application security risks. It's been updated regularly since 2003, and the same vulnerability classes appear on it repeatedly — not because developers don't know about them, but because they're easy to introduce under deadline pressure and easy to miss in code review.
- Injection (SQL, command, LDAP). Unsanitized user input passed directly to a database query or system command. The fix is parameterized queries and prepared statements — never string concatenation with user-controlled data. Still the most exploited vulnerability class despite being fully understood for over 20 years.
- Broken authentication. Weak session tokens, missing MFA, insecure password storage (MD5, SHA-1 without salting), and credentials exposed in logs or URLs.
- Insecure direct object references. An API that returns user data based on an ID in the URL without verifying the requester owns that ID. Changing
/api/users/1234to/api/users/1235returns someone else's data. - Security misconfiguration. Default credentials left unchanged, verbose error messages that expose stack traces, unnecessary services enabled, cloud storage buckets set to public.
- Vulnerable and outdated dependencies. Using libraries with known CVEs. This category has grown significantly with the rise of supply chain attacks targeting widely-used open source packages.
- Cryptographic failures. Sensitive data transmitted over HTTP, stored without encryption, or encrypted with weak or deprecated algorithms.
Secure Coding Fundamentals
The majority of OWASP Top 10 vulnerabilities are prevented by a small set of coding practices applied consistently:
Input Validation and Sanitization
Never trust data from outside your application boundary — user input, API responses, file uploads, environment variables. Validate type, length, format, and range at every entry point. Reject inputs that don't conform; don't try to sanitize malicious input into safe input. Validation at the API boundary is mandatory; validation deeper in the call stack is defense in depth.
Parameterized Queries, Always
SQL injection is eliminated entirely by parameterized queries (also called prepared statements). The database driver treats the parameter as data, not as part of the query syntax — it's structurally impossible to inject SQL through a parameter. There is no legitimate reason to build SQL strings by concatenating user input in 2026.
Output Encoding
Cross-site scripting (XSS) is prevented by encoding output appropriately for its context — HTML encoding for HTML content, JavaScript encoding for JS contexts, URL encoding for query parameters. Most modern frontend frameworks (React, Vue, Angular) encode output by default; the common failure pattern is explicitly opting out of encoding via dangerouslySetInnerHTML or equivalent.
Least Privilege in Code
Service accounts and database users used by application code should have only the permissions required for their specific function. A read-only API service connects to the database with a read-only credential. A background job that processes orders doesn't need access to the user management tables. Least privilege limits the blast radius of a compromise — an attacker who exploits the order processing service can't exfiltrate your entire user database.
Secrets Management: The Most Common Codebase Liability
Hardcoded credentials — database passwords, API keys, service account tokens — in source code is one of the most frequently exploited vulnerability patterns and one of the most preventable. Secrets committed to a git repository are effectively public: every developer who has ever cloned the repo has them, and git history preserves them even after deletion.
The correct pattern:
- Never commit secrets to version control. Use a pre-commit hook (git-secrets, detect-secrets, truffleHog) that scans staged changes for credential patterns before they're committed. Add
.envfiles to.gitignoreat project creation, not after the first accidental commit. - Use a secrets manager. AWS Secrets Manager, HashiCorp Vault, Azure Key Vault, or GCP Secret Manager. Application code fetches credentials at runtime from the secrets manager using its own IAM identity — no credentials in config files, environment variable files, or code.
- Rotate secrets regularly. Secrets managers support automatic rotation for common credential types. Rotation limits the window of exposure if a credential is compromised — and forces your application to handle credential refresh correctly rather than assuming credentials never change.
- Audit secret access. Every secrets manager provides access logs. Review them. An application that normally fetches a database credential once at startup should not be fetching it 10,000 times per hour.
Dependency Security: The Supply Chain Risk
Modern applications have hundreds to thousands of transitive dependencies. Each one is a potential attack surface. The 2021 Log4Shell vulnerability affected hundreds of thousands of applications — most of which didn't know they were using Log4j because it was a transitive dependency pulled in by something else.
Software Composition Analysis (SCA)
SCA tools scan your dependency tree against known vulnerability databases (NVD, GitHub Advisory Database, Snyk) and flag packages with CVEs. Integrate SCA into your CI pipeline so every pull request is checked: Snyk, OWASP Dependency-Check, npm audit, pip-audit, or GitHub's built-in Dependabot. Block merges when high-severity vulnerabilities are introduced; require review for medium.
Pin Dependencies to Exact Versions
Floating version ranges (^1.2.0, >=2.0) allow automatic minor and patch version updates. Supply chain attacks target this pattern by publishing malicious versions that satisfy the range. Pin to exact versions and use lockfiles (package-lock.json, requirements.txt with pinned versions, Cargo.lock). Update dependencies deliberately and with review, not automatically.
Audit Packages Before Adding Them
Before adding a new dependency, check: How many downloads per week? How recently was it maintained? Who owns it, and could the ownership have been transferred to a malicious actor? Does it request permissions inconsistent with its stated purpose? A utility package that needs network access and filesystem permissions is a red flag.
Static Application Security Testing (SAST) in CI/CD
SAST tools analyze source code for vulnerability patterns without executing it. They catch injection vulnerabilities, insecure API usage, hardcoded secrets, and common logic errors at the code level, before any deployment.
Integrate SAST into your CI pipeline as a blocking check:
- Semgrep — fast, rules-based, supports custom policies, runs in seconds
- CodeQL (GitHub) — deep semantic analysis, excellent for finding logic vulnerabilities across large codebases
- Bandit — Python-specific, catches common Python security mistakes
- ESLint security plugins — catches JavaScript/TypeScript security anti-patterns in the editor and CI
The goal is not zero findings — most codebases have false positives. The goal is a tuned ruleset that catches genuine vulnerabilities with a manageable false positive rate, enforced as a hard CI gate for high-severity findings.
Security in Code Review
Automated tooling catches pattern-based vulnerabilities. Code review catches logic vulnerabilities that tools can't model — authorization bypasses, race conditions, business logic flaws. Security-conscious code review asks:
- Does this endpoint verify the requester is authorized for this specific resource, not just authenticated?
- Are all database queries parameterized? Is any user input going near a query builder?
- Are there any new secrets, tokens, or credentials introduced? Where do they come from at runtime?
- Does this new dependency have a clean security record? What permissions does it need?
- Are error messages in this code exposing internal state, stack traces, or data to the caller?
Shifting Security Left: Building It Into the Pipeline
"Shift left" means finding security issues earlier in the development process — in the IDE and PR review, not in production or a quarterly penetration test. The cost of fixing a vulnerability increases by roughly 10x at each stage: code → PR review → staging → production → post-breach.
A minimal shift-left pipeline for a modern software team:
- IDE plugins — Semgrep, Snyk, or SonarLint running in the developer's editor, flagging issues as code is written
- Pre-commit hooks — secret scanning (detect-secrets), linting, and fast SAST before a commit is made
- CI pipeline gates — SCA for dependency vulnerabilities, full SAST run, container image scanning if applicable
- PR review checklist — explicit security questions in the review template so reviewers don't skip the security lens
- Periodic DAST — dynamic scanning against a running staging environment to catch issues SAST misses
The Bottom Line
Code security isn't a separate discipline from software development — it's the discipline of writing software that behaves correctly under adversarial input. The tools to catch the most common vulnerability classes are free, fast, and integrate directly into the development workflow. The barrier is almost never capability. It's the absence of a process that makes security checks automatic and unavoidable.
Start with parameterized queries and secrets management — those two practices alone eliminate the most frequently exploited vulnerability classes. Add SAST and SCA to your CI pipeline. Make security a required element of code review. The compounding effect of these practices on your security posture is significant and the implementation cost is low.
Need Help Building Security Into Your Development Process?
Ez IT Expert helps engineering teams implement secure development practices — from secrets management and CI pipeline security gates to code review processes and developer security training. Book a free 30-minute call to discuss your current posture and where the highest-leverage improvements are. See our security services.
Book a Free Security Review →