Secure Coding Practices Lab

A capstone review process: validate-input/encode-output, insecure framework defaults, a structured code review checklist, and dependency scanning as secure coding, not just ops.

Medium 65m 3 tasks

Learning Objectives

  • Apply the 'validate input, encode output' principle across HTML, JS, and API boundaries
  • Identify insecure defaults in common web framework configurations and correct them
  • Conduct a structured security code review using a repeatable checklist
  • Explain why dependency scanning is part of secure coding, not just operations
  • Apply defense-in-depth thinking to a single code change, not just architecture-level decisions

Bringing It All Together

Every vulnerability class covered across Web Development, Databases, and Web Security traces back to the same handful of coding habits. This lab is a capstone: a repeatable checklist and review process for catching these issues in your own code, before they ever reach a pentest report.

The Universal Rule: Validate Input, Encode Output

Nearly every injection vulnerability (SQL injection, XSS, command injection) comes down to one broken rule:

  • Validate input — reject or sanitize data as early as possible, based on what it's supposed to be (an email, a positive integer, one of a fixed set of values), not a blocklist of "bad" characters
  • Encode output — for the context it's being written into (HTML-encode for HTML, use parameterized queries for SQL, JSON-encode for JSON), never assume upstream validation makes this step unnecessary

The two are not substitutes for each other: input validation limits what data enters your system; output encoding ensures that whatever data is there can't be misinterpreted as code by whatever it's rendered into.

Insecure Defaults: What Frameworks Get Wrong Out of the Box

Framework setting Insecure default Secure correction
Express.js No security headers set Add helmet() middleware
Django DEBUG = True in production DEBUG = False, custom error pages
Any ORM Raw SQL string concatenation available Always use the ORM's parameterized query builder
Cookies No Secure/HttpOnly/SameSite flags Set all three explicitly

Frameworks optimize their defaults for a smooth first-run developer experience, not a hardened production deployment — assume every default needs a security review, not just the parts you changed.

A Structured Security Code Review Checklist

  1. Auth & access control — is every endpoint's authorization check present and correct, not just "is the user logged in"?
  2. Input handling — is every external input (query params, body, headers, file uploads) validated before use?
  3. Output handling — is every value rendered into HTML/SQL/shell/JSON properly encoded for that specific context?
  4. Secrets — are credentials, API keys, and tokens absent from source code and version control history?
  5. Error handling — do error paths avoid leaking stack traces, file paths, or internal implementation details?
  6. Dependencies — does the change introduce or upgrade a dependency, and if so, has it been checked for known CVEs?

Dependency Scanning: Secure Coding, Not Just Ops

A perfectly-written function that calls a library with a known critical CVE is still vulnerable — this is why tools like npm audit, pip-audit, or Dependabot belong in the same review process as manual code inspection, not treated as a separate, later "ops" concern. The vulnerable code, from the application's perspective, is still your code path, even though you didn't write the vulnerable line yourself.

Defense in Depth at the Code Level

Defense in depth isn't only an architecture-diagram concept — it applies to a single function. A database query should be parameterized and the calling code should enforce least-privilege database credentials and the API layer above it should validate input types — each layer assuming the others might fail, rather than one control being the application's only line of defense.

Common Pitfalls

  • Relying on client-side validation alone, forgetting it's trivially bypassed by anyone who controls their own HTTP requests
  • Blocklisting specific "dangerous" characters instead of validating against an allowlist of what's actually expected
  • Treating a security code review as a one-time gate instead of a habit applied to every change, including "small" ones
  • Assuming a popular, well-maintained dependency can't have a vulnerability — checking is cheap; assuming is not

Input validation and output encoding defend at two different points in the data's journey through the system, so neither replaces the other.

✦ Answer the questions to complete this task

Why are input validation and output encoding both necessary, rather than one making the other redundant?

Each of the three key cookie flags closes off a distinct attack vector against session cookies.

✦ Answer the questions to complete this task

Which cookie attributes should be explicitly set to harden session cookies?

From the application's runtime perspective, a vulnerable dependency's code is functionally no different from a vulnerable line you wrote yourself.

✦ Answer the questions to complete this task

Why does a known-vulnerable dependency count as part of secure coding, not just an operations concern?

💪 Exercises & Challenges

📝 MCQ Medium +20 XP

Secure Coding Practices Lab MCQ

Test your understanding of Secure Coding Practices Lab.

Start →
⚙️ Practical Medium +35 XP

Run a Structured Code Review

Given a Node.js/Express route handler that takes a username query parameter and inserts it directly into a raw SQL string, returns raw error messages including stack traces to the client, and sets a s

Start →
🚩 Challenge Medium +55 XP

Evaluate a Risky Dependency Justification

A code review of a pull request finds: (1) a new dependency was added that npm audit flags with a 'critical' severity CVE for remote code execution, (2) the PR author argues 'we don't call the vulnera

Start →