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 pageshowhide
explore
- Input Validation & Sanitization5 questions
- Output Encoding & Injection Theory4 questions
- SQL Injection5 questions
- OS Command Injection5 questions
- Path Traversal6 questions
- Insecure Deserialization Risks5 questions
- Secrets Management6 questions
- Sensitive Data in Memory & Transit5 questions
- Integer Overflow as a Security Bug4 questions
- AI Engineerrole
- AI Red Teamingrole
- API Designskill
- Android Developerrole
- Backend Developerrole
- Blockchain Developerrole
- Cyber Security Expertrole
- Data Engineerrole
- DevOps / SRE Engineerrole
- DevSecOps Engineerrole
- Frontend Developerrole
- Full Stack Developerrole
- GraphQLskill
- Java Backend Developerrole
- Java SDETrole
- Kotlin Backend Developerrole
- Machine Learning Engineerrole
- QA Engineerrole
- SQLskill
- Software Architectrole
- iOS Developerrole
questions
page 2 of 2Walk 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?
basics
~20 sThe 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.
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?
basics
~20 sRank 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.
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?
basics
~20 sSafety 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.
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.
basics
~20 sWiping 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.
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?
basics
~20 sMap 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.
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?
basics
~20 sBoth 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.
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?
basics
~20 sDeclare 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.
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?
basics
~20 sThe 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.
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?
basics
~20 sRank 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.
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.
basics
~20 sDraw 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.
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?
basics
~20 sMake 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.
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?
basics
~20 sStop 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.
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?
basics
~20 sInventory 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.
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?
basics
~20 sDefault 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.
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.
basics
~20 sFour 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.
showing 31–45 of 45