Domain 8 of 8 · Chapter 5 of 5

Secure Coding

The secure-coding model: untrusted input meeting a trusting sink

SQL injection, cross-site scripting, command injection, and the classic buffer overflow look like four different bugs, but they are one event wearing four costumes: data an attacker controls reaches code that treats it as trusted. Read any source-level vulnerability scenario through that lens and you can name the weakness class and predict its root-cause defense before the answer options load, because the durable fix always breaks the same chain at the point of consumption, not at the list of payloads. That one idea, paired with the CIA triad and layered defense-in-depth you already know, unifies the entire subtopic. SQL injection is attacker input reaching a database query; cross-site scripting (XSS) is attacker input reaching an HTML page; command injection is attacker input reaching a shell; a buffer overflow is attacker input reaching a fixed-size memory region. The figure shows the model: untrusted input first passes a cross-cutting input-validation gate, and whatever survives reaches a sink that has its own root-cause defense.

Two cross-cutting defenses recur often enough to name once here and reuse throughout. The first is input validation, and the load-bearing detail is its direction: validate against an allow-list of known-good input (the precise format, length, and character set you expect), not a deny-list of known-bad characters, because you cannot enumerate every malicious input an attacker might craft, so a deny-list always has a gap. The second is context-aware output encoding: when data leaves your application into another interpreter (a browser, a query, a shell), encode it so that interpreter renders it as inert data rather than executable instructions. Input validation constrains what comes in; output encoding neutralizes what goes out. Neither alone is complete, which is why defense in depth pairs them.

The rest of this page applies that model in three passes: the per-weakness mechanics (the canonical defense for each named vulnerability class), the API and software-defined-security surfaces where the same defenses move to a new boundary, and the exam-pattern recognition that turns the model into points. Throughout, defenses are stated at CISSP altitude (parameterize the query, encode for the context, enforce authorization server-side) never as a single language's syntax.

UntrustedinputInput validation(allow-list)DB query → parameterized queryHTML response → output encodingOS command → safe command APIMemory buffer → bounds checkingcross-cutting first lineeach sink gets its own root-cause defense
The data-flow defense model: untrusted input passes a cross-cutting input-validation gate, then each sensitive sink (database, browser, shell, memory) applies its own root-cause defense.

Per-weakness mechanics and the standards that name them

This section gives the canonical, root-cause defense for each named weakness class, and the taxonomies that let tools and teams refer to them precisely. It reuses the input-validation and output-encoding model from the previous section without re-deriving it.

Injection: separate code from data

Injection is the archetype. For SQL injection, OWASP's primary defense is the prepared statement with parameterized queries, because it forces "the developer to define all SQL code first and pass in each parameter to the query later[1]," so that "the database will always distinguish between code and data, regardless of what user input is supplied." That separation is why "an attacker cannot change the intent of a query, even if SQL commands are inserted." OWASP's priority order is explicit: prepared statements first, then safely-implemented stored procedures, then allow-list input validation for the cases where a bind variable cannot be used (e.g. a table name), and escaping user input is "STRONGLY DISCOURAGED" as a fragile, database-specific last resort. The same code-versus-data principle generalizes: OS command injection is defeated by avoiding the shell and calling a parameterized command API with an allow-list of arguments; LDAP injection by escaping for the LDAP context.

Cross-site scripting: encode for the destination context

XSS is injection into a web page: untrusted input is reflected into HTML and the browser executes it as script. The defense is output encoding that matches where the data lands, because the parsing rules differ by context and "wrong encoding methods may introduce weaknesses[2]": HTML-body encoding converts < to &lt;, an HTML-attribute context needs attribute encoding, a JavaScript context needs JavaScript encoding, and a URL context needs percent-encoding; they are not interchangeable. Input validation is a useful defense-in-depth layer but cannot be the sole control, since "context awareness cannot be determined at the HTTP request layer[2]" where input validation runs. A Content Security Policy is a further mitigating layer. In the OWASP Top 10:2021 taxonomy, XSS is folded into the Injection category rather than standing alone.

Broken access control: enforce authorization server-side, every request

Broken access control is the failure to enforce that "users cannot act outside of their intended permissions[3]." It is the #1 risk in the OWASP Top 10:2021, having "moved up from the fifth position," with "94% of applications[3] tested for some form of broken access control." The coding defenses are structural: deny by default, enforce authorization on the server for every request (never trust a hidden form field, a disabled button, or a client-side check), and check ownership before acting on an object so a user cannot read or modify another user's record by changing an identifier.

Memory-safety weaknesses: bounds and range checks

A buffer overflow writes past the end of a fixed-size buffer because no bounds check constrains the write; the consequences range from a crash to attacker code execution by overwriting a return address. The root-cause defenses are bounds checking and memory-safe languages or functions; compiler and OS mitigations (stack canaries, Address Space Layout Randomization, and Data Execution Prevention / non-executable stacks) raise the bar but do not remove the flaw. An integer overflow is arithmetic that exceeds the type's range and wraps silently, often producing an undersized allocation or a bypassed length check that then enables a buffer overflow, so range and overflow checks belong before the value is used to size or index memory. A race condition / time-of-check-to-time-of-use (TOCTOU) flaw arises when state changes between a security check and the action that relied on it; the fix is to make check-and-act a single atomic operation (locking, atomic APIs) rather than two separable steps.

The taxonomies: what each artifact is FOR

Four names recur, and the exam tests whether you know which is which. The OWASP Top 10 is "a standard awareness document for developers and web application security[4]": a ranked awareness list of risk categories, not a checklist. CWE (MITRE's Common Weakness Enumeration) is the dictionary of weakness types: CWE-89 is SQL injection, CWE-79 is XSS, CWE-120 is a classic buffer overflow, a stable identifier tools and reports cite to name a defect precisely. CVE is a different thing entirely: one specific vulnerability instance in one product (a CVE is an instance of a CWE). The OWASP Application Security Verification Standard (ASVS) is a tiered catalog of security requirements you verify an application against, and CERT/SEI secure coding standards give language-specific rules. Top 10 = themes, CWE = named weaknesses, ASVS = requirements to verify, CVE = one real-world instance. The figure groups those weakness classes into families, each weakness paired with the structural defense the exam rewards.

weakness classroot-cause defenseInjectionSQL injectionParameterized query / prepared statementOS command injectionSafe command API, no shellLDAP injectionEscape for the LDAP contextCross-site scripting (XSS)Input reflected into a pageContext-aware output encodingBroken access controlActing outside permissionsServer-side authz each requestMemory-safety weaknessesBuffer overflowBounds checking / memory-safe langInteger overflowRange check before sizing memoryRace condition (TOCTOU)Atomic check-and-actcode-versus-data separation enforced at the point of consumption
Each weakness class maps to one structural root-cause defense; the families share the code-versus-data principle, fixed at the point of consumption.

Securing APIs and software-defined security

This section moves the same defenses to two surfaces the exam treats as distinct: the API call boundary and security expressed as code. It introduces no new defense principle, only new places the principles apply.

API security: authorize the object, not just the caller

An API exposes application logic directly to programmatic callers, so the controls are the same authentication, authorization, validation, and rate-limiting you already know, applied at every call. The OWASP API Security Top 10 (2023) names the dominant failures, and the top one is Broken Object Level Authorization (API1:2023): an authenticated user requests another user's object simply by changing an ID in the request, because the server authenticated the caller but never checked that this caller may access that object. The fix is an ownership/authorization check on every object reference, server-side. A related entry, Broken Object Property Level Authorization (API3:2023), combines the older 'excessive data exposure' and 'mass assignment' problems: returning or accepting more object fields than the caller should see or set, then relying on the client to filter. Unrestricted Resource Consumption (API4:2023) is why rate limiting is a first-class API control: without it, an API request that consumes "network bandwidth, CPU, memory, and storage[5]" can be driven to a denial of service or a brute-force of credentials. Schema-based request validation (rejecting any request body or parameter that does not match a declared schema) is the input-validation gate from the model section, expressed for APIs.

Software-defined security: controls as version-controlled code

Software-defined security expresses security controls as code and configuration rather than hand-applied settings, so they are version-controlled, peer-reviewed, tested, and applied identically across every environment. Policy-as-code evaluates a declarative policy in the deployment pipeline; infrastructure-as-code templates define network segmentation, identity, and security-group rules as files that go through the same review and audit as application code. The security payoff is twofold: consistency (the same control everywhere, no drift between a hand-configured production box and its staging twin) and auditability (every change is a reviewable, attributable commit). This is the secure-coding mindset applied to the platform: the configuration that enforces a control is itself code, so it inherits code's review, testing, and rollback discipline. The figure groups the two surfaces: each API failure beside its server-side fix, and the two code-as-control forms beside the consistency and auditability they buy.

API security: authorize the object, not just the callerBroken object-level authz (API1)Ownership check on every objectBroken object-property authz (API3)Field-level authorizationUnrestricted resource use (API4)Rate limitingRequest validationSchema-based input gateSoftware-defined security: controls as version-controlled codePolicy-as-codeInfrastructure-as-codeConsistency (no drift)Auditability (reviewable commits)same defenses, two new boundaries
Two surfaces, one mindset: API calls authorize the object per request; software-defined security makes controls version-controlled code.

Exam-pattern recognition

This section turns the model into points: it names the stems the exam uses and the trap each one dangles. It introduces no new facts; every claim traces to a section above.

Name the weakness, then pick its root-cause defense

The stem describes a flaw; map it to the defense the exam rewards. Untrusted input concatenated into a database query → SQL injection (answer: parameterized query / prepared statement, not 'escape the input' and not 'add a WAF'). User input reflected into a page and executed by the browser → XSS (answer: context-aware output encoding for where the data lands; input validation is only defense in depth). A user reaching another user's record by changing an ID → broken object-level authorization / broken access control (answer: server-side authorization check on every object, deny by default). Writing past a fixed-size buffer → buffer overflow (answer: bounds checking / memory-safe language; canaries, ASLR, DEP are hardening layers). Two steps with a gap between check and use → race condition / TOCTOU (answer: make check-and-act atomic).

The traps, stated as the wrong move

  • Reaching for a deny-list (blocklist) of bad characters: choosing 'strip dangerous characters' or 'block known-bad input' when the defensible answer is an allow-list of known-good input; you cannot enumerate all bad input.
  • Escaping instead of parameterizing for SQL injection: picking 'escape single quotes' when prepared statements are the primary defense and escaping is OWASP-discouraged and fragile.
  • Treating a WAF as the fix rather than a compensating layer: a web application firewall buys time, but the root-cause control is the secure-coding practice (parameterize, encode, authorize); 'add a WAF' is the distractor when the stem describes a code-level flaw.
  • Validating input but forgetting context-specific output encoding for XSS: input validation cannot be the sole XSS control because context awareness is not available at the request layer; the answer must include encoding for the output context.
  • Authenticating the caller but not authorizing the object: assuming a logged-in user is allowed to act on any object they can name; object-level authorization must be checked per request.
  • Confusing the taxonomies: answering 'CVE' when the question wants the weakness type (CWE), or treating the OWASP Top 10 as a compliance checklist rather than an awareness ranking.

When the question is testing a neighbor, not this subtopic

If the stem is about the tool that finds the flaw (static analysis (SAST), dynamic analysis (DAST), fuzzing, software composition analysis) that is dev-environment-security / software-security-effectiveness, not secure coding. If it asks where in the lifecycle security belongs (threat modeling, security requirements, shifting left), that is sdlc-security. If it asks about risk in purchased or imported components (SBOM, third-party/open-source evaluation), that is acquired-software-security. This subtopic owns the code you write and the source-level weakness classes within it.

Common source-level weakness classes and their canonical root-cause defense

Weakness classRoot causeCanonical defense (best answer)
SQL injection (CWE-89)Untrusted input concatenated into a query stringParameterized queries / prepared statements (code and data separated)
Cross-site scripting / XSS (CWE-79)Untrusted input reflected into a page without encodingContext-aware output encoding; input validation as defense in depth
OS command injection (CWE-78)Untrusted input passed to a shell/command interpreterAvoid the shell; use parameterized APIs; allow-list arguments
Broken access control (CWE-284)Authorization not enforced (or enforced only client-side)Server-side authorization on every request; deny by default
Buffer overflow (CWE-120)Writing past a fixed-size buffer (no bounds check)Bounds checking; memory-safe language/functions; canaries, ASLR, DEP
Integer overflow (CWE-190)Arithmetic exceeds the type's range, wrapping silentlyRange/overflow checks before allocation or indexing
Race condition / TOCTOU (CWE-367)State changes between a check and its useAtomic operations; locking; check-and-act as one step

Decision tree

First: allow-list input validation(cross-cutting, not a deny-list)Input names an object thecaller wants to act on?YesServer-sideauthorizationNoInput reaches an interpreter(query, page, shell)?DB queryHTML pageOS commandParameterizedqueryContext-awareoutput encodingSafe commandAPI (no shell)NoInput sizes or indexesa memory buffer?YesBounds checking /memory-safe code

Sharp facts the exam loves — give these one last read before exam day.

Cheat sheet

Sharp facts the exam loves — scan these before test day.

Most source-level vulnerabilities are one event: untrusted input reaching a trusting sink

Injection, cross-site scripting, command injection, and buffer overflows are different symptoms of the same root cause: attacker-controlled data is consumed by code that treats it as trusted. The durable fix breaks that chain at the point of consumption (parameterize the query, encode for the output context, bound the write), not by trying to enumerate every malicious payload. Recognizing the shared cause is what lets you pick the structural defense instead of a generic one.

Trap Reaching for a signature filter that enumerates and blocks known malicious payloads instead of breaking the input-to-sink chain at the point of consumption.

2 questions test this
Validate input against an allow-list of known-good, never a deny-list of known-bad

Input validation should accept only input matching the exact expected format, length, and character set (an allow-list / whitelist), because you cannot enumerate every malicious input an attacker might craft, so a deny-list of 'known bad' characters always leaves a gap. Allow-list validation is the cross-cutting first line of defense, but it is defense in depth: it does not replace the sink-specific control (parameterized query, output encoding).

Trap Choosing 'strip or block dangerous characters' (a deny-list) over 'accept only known-good input'. The deny-list is incomplete because not all bad input can be enumerated.

7 questions test this
Defeat SQL injection with parameterized queries, not by escaping characters

OWASP's primary defense against SQL injection is the prepared statement with parameterized queries: it forces the developer to define all SQL code first and bind each parameter later, so the database always distinguishes code from data and an attacker cannot change the query's intent. OWASP's priority order is prepared statements first, then safely-implemented stored procedures, then allow-list validation where a bind variable is impossible (e.g. a table name), and escaping user input is explicitly discouraged as fragile and database-specific.

Trap Selecting 'escape special characters in the input' as the SQL-injection fix. OWASP strongly discourages escaping; parameterized queries are the primary defense.

6 questions test this
Prevent XSS with output encoding matched to the destination context

Cross-site scripting is defeated by encoding untrusted data for exactly the context it lands in: HTML body, HTML attribute, JavaScript, CSS, and URL contexts each have different parsing rules, and using the wrong encoding can itself introduce a weakness. Input validation helps as defense in depth but cannot be the sole XSS control, because the output context is not known at the HTTP request layer where input validation runs; a Content Security Policy is an additional mitigating layer.

Trap Relying on input validation alone to stop XSS. Context awareness is unavailable at the request layer, so output must still be encoded for where it is rendered.

4 questions test this
Defeat command injection by avoiding the shell and using a safe command API

OS command injection occurs when untrusted input is passed to a shell or command interpreter. The root-cause fix is to avoid invoking a shell at all and instead call a parameterized command API with an explicit allow-list of permitted arguments, so attacker input can never be parsed as a new command. The same code-versus-data separation that defeats SQL injection applies here.

Trap Escaping or sanitizing shell metacharacters in the input rather than avoiding the shell entirely and calling a parameterized command API.

Broken access control is the #1 OWASP Top 10:2021 risk: enforce authorization server-side

Broken Access Control moved up to the #1 position in the OWASP Top 10:2021 (from 5th), with 94% of tested applications showing some form of it; access control means users cannot act outside their intended permissions. The coding defenses are structural: deny by default, enforce authorization on the server for every request, and check object ownership before acting, never trust a hidden field, a disabled button, or a client-side check.

Trap Enforcing access control only in the client (hiding a button, disabling a field). The authorization check must run server-side on every request.

Buffer overflows are fixed by bounds checking; canaries, ASLR, and DEP only raise the bar

A buffer overflow writes past a fixed-size buffer because no bounds check constrains the write, and overwriting a return address can let an attacker execute code. The root-cause defenses are bounds checking and memory-safe languages or functions. Compiler and OS mitigations (stack canaries, Address Space Layout Randomization (ASLR), and Data Execution Prevention (DEP / non-executable stack)) make exploitation harder but do not remove the underlying flaw.

Trap Treating ASLR/DEP/stack canaries as the fix. They are hardening layers that raise the cost of exploitation, not a substitute for bounds checking.

Integer overflow wraps silently and often enables a later buffer overflow

An integer overflow is arithmetic that exceeds the type's range and wraps around silently, frequently producing an undersized allocation or a bypassed length check that then enables a buffer overflow. The defense is to perform range and overflow checks before the value is used to size or index memory, not after.

Trap Validating the arithmetic result after the operation, when the value has already wrapped, instead of range-checking the operands before the computation.

Fix a race condition (TOCTOU) by making check-and-act atomic

A race condition, specifically a time-of-check-to-time-of-use (TOCTOU) flaw, occurs when state changes between a security check and the action that relied on it, so the action operates on conditions that no longer hold. The fix is to make the check and the use a single atomic operation, using locking or atomic APIs, rather than two separable steps an attacker can interleave.

Trap Re-checking the condition immediately before use to shrink the window instead of making check-and-act atomic, since a narrower window is still a window an attacker can interleave.

1 question tests this
Know what each weakness taxonomy is FOR: Top 10, CWE, CVE, ASVS, CERT

The OWASP Top 10 is a ranked awareness document of web-application risk categories, not a checklist. CWE (MITRE's Common Weakness Enumeration) is the dictionary of weakness types, e.g. CWE-89 SQL injection, CWE-79 XSS. CVE is a different thing: one specific vulnerability instance in one product (an instance of a CWE). ASVS is OWASP's tiered catalog of requirements you verify an application against, and CERT/SEI standards give language-specific coding rules.

Trap Answering 'CVE' when the question asks for the weakness type. A CVE is one instance in a product, whereas the weakness category is a CWE.

2 questions test this
NIST SP 800-218 (SSDF) organizes secure development into four practice groups

The NIST Secure Software Development Framework (SSDF), SP 800-218, is a set of high-level secure software development practices meant to be integrated into any SDLC rather than replacing it. Its four practice groups are Prepare the Organization (PO), Protect the Software (PS), Produce Well-Secured Software (PW), and Respond to Vulnerabilities (RV).

The top API risk is Broken Object Level Authorization: authorize the object, not just the caller

Broken Object Level Authorization (API1 in the OWASP API Security Top 10) is the dominant API failure: an authenticated user reaches another user's object simply by changing an ID in the request, because the server authenticated the caller but never verified that this caller may access that specific object. The fix is an ownership/authorization check on every object reference, performed server-side.

Trap Assuming an authenticated caller may act on any object whose ID they can supply. Authorization must be checked per object, not just at login.

Broken Object Property Level Authorization covers excessive data exposure and mass assignment

Broken Object Property Level Authorization (OWASP API Security Top 10) combines the older 'excessive data exposure' and 'mass assignment' problems: the API returns more object fields than the caller should see, or accepts more fields than the caller should set, then relies on the client to filter. The fix is to authorize access at the property level on the server and return or accept only the fields appropriate to the caller, never filtering in the UI.

Trap Returning a full object and hiding extra fields in the client. The sensitive properties still travel to the caller and can be read directly.

Rate-limit APIs to prevent unrestricted resource consumption and brute force

Rate limiting is a first-class API control because an API request consumes network bandwidth, CPU, memory, and storage; without limits an attacker can drive a denial of service or brute-force credentials and other guessable values. This corresponds to Unrestricted Resource Consumption in the OWASP API Security Top 10, and pairs with schema-based request validation that rejects any body or parameter not matching a declared schema.

1 question tests this
Software-defined security expresses controls as version-controlled code

Software-defined security defines security controls as code and configuration (policy-as-code and infrastructure-as-code for segmentation, identity, and security-group rules) rather than hand-applying settings. The payoff is consistency (the same control everywhere, no drift between a hand-configured box and its twin) and auditability (every change is a reviewable, attributable commit), inheriting code's review, testing, and rollback discipline.

1 question tests this
A WAF is a compensating layer, not the root-cause fix for a code-level flaw

A web application firewall can filter some malicious requests and buy time, but it is a compensating control layered on top of the application, not the root-cause defense. When a scenario describes a code-level vulnerability such as SQL injection or XSS, the correct answer is the secure-coding practice (parameterize the query, encode the output, validate input). The WAF is supplementary.

Trap Selecting 'deploy a WAF' as the fix for a described code-level injection flaw. It mitigates but does not remove the vulnerability; the code-level control does.

Server-side validation is the only authoritative control; client-side checks are trivially bypassable

All security-relevant input validation must be enforced on the server and treat every client input as untrusted, because an attacker can disable JavaScript, use a browser dev tool, or send crafted HTTP requests through a proxy that never run the client-side checks. Client-side validation is for user-experience feedback only, never for security.

Trap Thorough client-side JavaScript validation is NOT a substitute and does not make server-side validation redundant.

5 questions test this

References

  1. OWASP SQL Injection Prevention Cheat Sheet
  2. OWASP Cross Site Scripting Prevention Cheat Sheet
  3. OWASP Top 10:2021: A01 Broken Access Control
  4. OWASP Top Ten Project
  5. OWASP API Security Top 10 (2023)