Secure Coding Practices
Secure coding is the discipline of building software so that common attacks fail by design. It covers input handling, authorization, secrets, dependencies, CI/CD, logging, and the release process. Recent supply chain incidents show that secure coding no longer stops at application code. Your packages, editor extensions, build scripts, tokens, and deployment pipeline are also part of the product’s security boundary.1. Input Validation
Never trust data from users, clients, webhooks, files, APIs, queues, or third-party systems. Every input can be an attack path:- Form fields
- URL parameters
- HTTP headers
- Cookies
- File uploads
- API payloads
- Webhook events
- CSV imports
- AI tool outputs
- Messages from queues or workers
Validation Strategies
2. Output Encoding
Output encoding prevents untrusted data from becoming executable content in a browser.
Modern frameworks such as React, Angular, Vue, and Svelte escape output by default in normal templates. The risk returns when developers bypass those protections.
3. Parameterized Queries
Parameterized queries separate SQL code from user data.4. Authorization by Default
Authentication asks “who are you?” Authorization asks “what are you allowed to do?” Secure systems enforce authorization on the server for every sensitive object and action.Patterns
- Deny by default.
- Centralize authorization checks where practical.
- Check object ownership, not just route access.
- Use least privilege roles.
- Re-check authorization after state changes.
- Log authorization failures.
Anti-Pattern
Hiding an admin button in the UI but leaving the API endpoint unprotected is not authorization. Attackers can call the API directly.5. Secrets Management
Secrets include passwords, tokens, API keys, SSH private keys, signing keys, database URLs, webhooks secrets, and cloud credentials.Where Secrets Belong
Secret Hygiene
- Never hardcode secrets.
- Never commit
.envfiles. - Scan commits with tools such as gitleaks, trufflehog, or detect-secrets.
- Use short-lived credentials where possible.
- Scope tokens narrowly.
- Rotate secrets after exposure.
- Separate development, staging, and production secrets.
6. Dependency Security
Modern applications depend on open-source packages, containers, build plugins, editor extensions, and SaaS SDKs. Each one can introduce vulnerabilities or malicious behavior.Supply Chain Risks
- Known vulnerable dependency versions.
- Typosquatted packages.
- Compromised maintainer accounts.
- Malicious install scripts.
- Dependency confusion between public and private package names.
- Auto-updates that pull unreviewed code.
- Abandoned packages with no security fixes.
Controls
- Use lockfiles for reproducible installs.
- Review dependency diffs in pull requests.
- Run dependency scanning in CI.
- Remove unused packages.
- Prefer packages with active maintainers and clear ownership.
- Use private package namespaces to reduce dependency confusion.
- Restrict install scripts where possible.
- Monitor package publishes for unexpected releases.
7. Software Provenance and Build Integrity
Software provenance answers: where did this artifact come from, what source produced it, and what workflow built it?Practices
- Use protected branches.
- Require code review for critical paths.
- Require signed commits or signed releases where appropriate.
- Generate SBOMs for releases.
- Produce build attestations for important artifacts.
- Keep build logs.
- Isolate CI runners.
- Do not expose production secrets to untrusted pull request workflows.
- Pin third-party CI actions to specific versions or commits.
8. CI/CD Security
CI/CD systems are high-value targets because they can access source code, secrets, deployments, containers, cloud accounts, and package registries.CI/CD Controls
- Require branch protection on main branches.
- Use least-privilege service accounts.
- Separate build, test, staging, and production permissions.
- Avoid long-lived deployment tokens.
- Restrict who can modify workflows.
- Protect self-hosted runners.
- Require manual approval for production deploys when risk is high.
- Log secret access and deployment activity.
- Scan artifacts before release.
Pull Request Safety
Be careful when CI runs code from forks or untrusted contributors. That code may try to print secrets, modify workflows, or abuse runner permissions. Safer options:- Do not expose secrets to untrusted PRs.
- Use read-only tokens for validation jobs.
- Require maintainer approval before running privileged jobs.
- Review workflow changes carefully.
9. Secure Error Handling
Applications should fail safely and avoid leaking internal details.- Never show stack traces to end users.
- Do not return database URLs, file paths, secrets, or internal hostnames.
- Log enough detail for investigation.
- Use correlation IDs so support can connect user reports to logs.
- Fail closed for authentication and authorization errors.
10. Security Logging and Detection
Secure coding includes creating the evidence defenders need. Log security-relevant events:- Login success and failure
- MFA enrollment and disablement
- Password reset requests and completion
- Session revocation
- Role changes
- Permission changes
- API key creation and use
- OAuth app approvals
- Data exports
- Webhook failures
- Package publish events
- CI/CD workflow changes
- Passwords
- Session cookies
- MFA codes
- API tokens
- Full payment details
- Sensitive personal data unless there is a clear need and protection
11. Threat Modeling
Threat modeling identifies what can go wrong before code is shipped. Use STRIDE:
Apply STRIDE to:
- Authentication flows
- Admin panels
- Data export features
- Webhooks
- AI agent tools
- CI/CD workflows
- Package publishing
- Third-party integrations
Secure Coding Checklist
- Validate input server-side.
- Encode output by context.
- Use parameterized queries.
- Enforce authorization on the server.
- Store secrets outside code.
- Use least-privilege tokens.
- Scan for secrets before commit.
- Review dependency changes.
- Protect CI/CD workflows and runners.
- Log security events.
- Threat model sensitive workflows.
Practical Lab Ideas
- Add server-side validation to an API route.
- Fix an XSS bug by using contextual output encoding.
- Replace a vulnerable SQL query with a parameterized query.
- Add object-level authorization to an endpoint.
- Run a secret scanner on a sample repository.
- Create an SBOM and inspect transitive dependencies.
- Harden a CI workflow so untrusted PRs cannot access secrets.
- Threat model a package publishing workflow.
Key Takeaways
- Secure coding includes the build and release path.
- Authorization must be server-side and object-aware.
- Secrets need lifecycle management, not just hiding.
- Dependencies and extensions are attack surface.
- CI/CD deserves the same security attention as production.
- Good logs make response possible.
- Threat modeling catches missing controls before attackers do.