skip to content

Secure Coding Principles

The habits that kill whole categories of bugs at once — distrust every external input, fail closed, grant the least privilege that works, keep data from ever being read as code, and validate at trust boundaries. Interviewers ask about principles rather than individual CVEs because a candidate who reasons this way avoids the bugs they have not seen yet.

part ofApplication security & secure codingoverview, primer and where to startread it →
on this pageshow

questions

page 2 of 2

Walk the chain from a silent arithmetic wraparound to an attacker's actual capability. What determines whether the same wrap yields memory corruption, an authorisation bypass, or nothing at all?

level: seniorimportance: should knowfreq 42%

basics

~20 s

The wrap only matters through the sink it feeds. A wrapped size drives an undersized allocation that a full-length write then overruns; a wrapped length passes a bounds test and yields out-of-range access; a wrapped total or counter defeats a quota, price or expiry decision. What the value authorises decides the impact.

open as a page

A scanner reports three places in a codebase where a request value reaches a file operation. How do you reason about what an attacker actually gains from each, and how do you rank them against one another for fixing?

level: seniorimportance: should knowfreq 36%

basics

~20 s

Rank by reachability × privilege × sensitivity. Ask who can reach the sink, what the executing process can already touch, whether the sink reads, writes or deletes, and whether the result or an error timing leaks. Writes outrank reads because writes become execution.

open as a page

The string `../../config/key.pem` is an ordinary key in an object store, a traversal when joined onto a filesystem path, and something different again as a URL path segment travelling through a reverse proxy. What general rule does that force, and where does it put the enforcement?

level: seniorimportance: should knowfreq 32%

basics

~20 s

Safety is a relation between a name and a specific resolver, not a property of the string. So "sanitised" cannot be carried across a boundary: each resolver in the chain is its own boundary, and enforcement belongs adjacent to each sink, expressed in that sink's grammar.

open as a page

Suppose you do everything the memory-hygiene advice asks: hold the secret in a mutable buffer and overwrite it immediately after use. Give an honest account of what that guarantees and what it does not — including the mechanisms outside your program that can copy those bytes elsewhere — and say which controls actually bound the exposure.

level: seniorimportance: should knowfreq 35%

basics

~20 s

Wiping shortens the window, it does not guarantee erasure: relocating collectors leave stale copies, compilers can delete the wipe, and swap, hibernation, core dumps, copy-on-write forks and hypervisor snapshots copy memory outside your control. The real bound is restricting who can capture process memory.

open as a page

A reporting endpoint lets callers choose the sort column and direction, and in some deployments the table to read from. Placeholders cannot bind those positions. How do you build such a query safely, and why is an allowlist the only sound answer?

level: seniorimportance: should knowfreq 55%

basics

~20 s

Map the caller's opaque token to a fixed, code-owned identifier through a lookup table, and reject anything not in the table. Identifiers determine the plan, so they must be resolved before parsing — binding is impossible and quoting is a weak substitute.

open as a page

Teams often say "we use an ORM" or "all access goes through stored procedures, so injection is impossible." Under what conditions is each claim false, and does the same reasoning carry over to document-database query languages?

level: seniorimportance: should knowfreq 52%

basics

~20 s

Both claims describe a tool, not the invariant. An ORM is safe only where it builds the statement; string fragments and native-query escape hatches are not. A procedure is safe only if its body does not itself assemble dynamic SQL from its arguments. Document databases have the same defect in operator form.

open as a page

You own a public API that must accept free-text fields, arbitrary JSON documents and file uploads. Design the validation strategy: what fails closed, which layers exist, and how do you stop the validation code from becoming a vulnerability in its own right?

level: principalimportance: should knowfreq 40%

basics

~20 s

Declare one schema enforced identically at every entry point; impose size, depth, count and expansion limits during parsing, not after; keep free text unmodified and let sinks handle it; identify files by parsing, not by extension; and treat the validator itself as attack surface — bounded regexes, no external entity or schema fetching, reject rather than coerce.

open as a page

Some injection sinks are parsers you never invoke: a spreadsheet application opening an exported file, an operator's terminal displaying a log line, a mail server reading headers. What does correct output encoding mean when the interpreter runs outside your process, and how do you reason about it?

level: principalimportance: should knowfreq 26%

basics

~20 s

The rule is unchanged — encode for the grammar that will parse the value — but that grammar belongs to a consumer you do not control and may not know. So you use a real serializer for the format, constrain values to a closed set where the consumer's rules are unknowable, and treat every export or log line as a sink with an owner.

open as a page

You inherit a system with several hundred long-lived credentials spread across services, pipelines and machine accounts. How do you decide which ones to fix first, and what does "fix" mean for each?

level: principalimportance: should knowfreq 38%

basics

~20 s

Rank by exposure times privilege times data sensitivity, adjusted upward when the credential is shared, unattributable or hard to rotate. Fix in that order: build cheap rotation first, then split shared credentials per principal, narrow scope, shorten lifetime, and only then scan.

open as a page

Take a piece of sensitive data that enters at the edge of a distributed system and ends up encrypted in storage. Explain how you would reason about where it exists in cleartext along the way, and what design moves reduce the number of components that ever see the plaintext.

level: principalimportance: should knowfreq 25%

basics

~20 s

Draw the plaintext's path and count the components that can see it. Every hop that terminates a connection, parses, queues, caches, retries or logs holds a cleartext copy. Reduce the count: substitute a reference for the value early, and decrypt only inside the one component that needs it.

open as a page

You inherit a large, long-lived codebase with thousands of queries assembled by string concatenation. How would you drive injection risk toward zero over time, and what limits the damage in the meantime?

level: principalimportance: should knowfreq 36%

basics

~20 s

Make the unsafe path unrepresentable rather than hunting bugs: one query-construction API that accepts a static template plus bound values, a build-time ratchet so no new concatenation is added, risk-ranked migration of the existing sinks, and least-privilege plus data-level controls to cap blast radius while the work runs.

open as a page

A product feature genuinely requires running commands or programs that users supply — a build runner, a plugin hook, a conversion pipeline fed by user files. You cannot allow-list the command. How do you build this safely?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Stop trying to make the input safe and relocate the trust boundary: execution happens inside a disposable, unprivileged, isolated environment with no ambient credentials, no default egress and hard resource limits. Everything it produces — output, logs, filenames — is then untrusted input to you.

open as a page

You inherit a large system that moves natively serialized objects between services, into a shared cache, and into client-held session blobs. How would you eliminate this bug class rather than patch instances, and what holds the line while the migration runs?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

Inventory decode sites and their producers, set a target of schema-first codecs binding into code-chosen types, migrate behind a version tag, and delete the requirement where possible — client blobs become server-side references. Meanwhile: allow-list filters, budgets, least-privileged decoders, banned-API lint.

open as a page

You are setting the arithmetic policy for a codebase that does size, quota and money calculations on untrusted numbers across several languages. How do you decide between checked (fail-fast), saturating, wrapping and wider-type arithmetic, and where do you put the guarantee?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

Default to checked arithmetic that fails fast wherever the value authorises something. Allow saturating only where a clamped value is semantically correct, such as display or back-off caps. Wrapping is opt-in and must be named. Wider types are a range argument, never a fix. Put the guarantee in shared helpers and types, not in review discipline.

open as a page

A filename check passes, and yet the file that ends up being opened is not the file that was checked. Enumerate the mechanisms that let the string a validator inspects differ from the name a resolver acts on, and give the rule that eliminates the whole class.

level: principalimportance: nice to knowfreq 26%

basics

~20 s

Four mechanisms: another decode pass after the check, normalisation or platform mangling applied later, truncation at a layer boundary such as an embedded NUL, and re-resolution over a mutable namespace. The rule: resolve once to a handle, verify the handle, operate on the handle.

open as a page

showing 31–45 of 45