core practice · coding problem
Parameterise instead of escaping
Implement buildQuery(table, filters) returning { text, values }: a parameterised SQL string using $1, $2 … placeholders in order, plus the values array. Column names come from a fixed ALLOWED set — reject anything else by throwing. Never interpolate a value into the string.
The mechanism
Almost every one of these is the same bug: data crossing into a place where it is interpreted as code or as authority. Injection (SQLi, XSS) is untrusted input reaching an interpreter, and the fix is never escaping-by-hand but parameterisation and contextual output encoding. CSRF is different in kind — a confused deputy, where the browser helpfully attaches your cookies to a request your site did not initiate, which is why the defence is an unguessable token or SameSite rather than validation. CORS is not a defence at all; it relaxes the same-origin policy, so a permissive CORS header removes protection rather than adding it.
Expected evidence
buildQuery('users', {name:'ann', age:30}) -> { text: 'SELECT * FROM users WHERE name = $1 AND age = $2', values: ['ann', 30] }Try this drill in the practice workspace →
Hints when you need them
- Values are never concatenated. Identifiers cannot be parameterised, which is exactly why they need an allowlist.
- A value containing a quote must end up in `values` untouched, not escaped into `text`.
Watch for these mistakes
- Treating CORS as a security control — it grants access, it does not restrict it
- Escaping output once globally instead of per context; HTML, attribute, URL and JS contexts need different encodings
- Blocklisting dangerous input instead of parameterising the query
- Storing session tokens in localStorage, which is readable by any XSS you ever ship