EXERCISE 3 — Why A03 moved to #3 & absorbed XSS; the unifying principle ======================================================================= WHY A03 INJECTION MOVED FROM #1 TO #3 (2021): - Injection topped the list for years. It fell to #3 NOT because it became less dangerous, but because the PREVALENCE dropped: modern frameworks made the SAFE PATH THE DEFAULT. * ORMs and DB libraries parameterize queries automatically. * Template engines / frontend frameworks auto-escape output by default. * Safer APIs replaced shell-string building in many stacks. So fewer apps ship injectable code by default, which lowers the measured rate — and the Top 10 ranks by data including prevalence. Other categories (Broken Access Control) rose above it. WHY IT ABSORBED XSS: - In 2021, Cross-Site Scripting — previously its own Top 10 entry — was MERGED INTO A03 Injection. This formally recognises what the XSS course teaches: XSS is just INJECTION AIMED AT THE BROWSER (untrusted input parsed as HTML/JS by the browser, instead of SQL by a database). Same root cause, different interpreter, so it belongs in the same family/category. WHY THIS DOESN'T MEAN INJECTION IS "SOLVED": - "Less common by default" is not "gone." Injection still ranks #3 — it's common AND high-impact (data theft, auth bypass, and for command/template injection, full server RCE). - The safe defaults are easily bypassed: ORM RAW-QUERY hatches and string concatenation, framework escape hatches (dangerouslySetInnerHTML / v-html), shelling out with concatenated input, rendering user input as a template, and SECOND-ORDER injection from stored data. Every escape hatch reintroduces the bug. - So the discipline still matters everywhere; frameworks reduce the odds, they don't remove the responsibility. THE ONE PRINCIPLE UNIFYING THE WHOLE FAMILY: - UNTRUSTED INPUT MUST STAY DATA AND NEVER BECOME CODE. Injection happens when input crosses a boundary where an interpreter parses it as instructions. The fix is always to KEEP DATA OFF THE CODE CHANNEL — send the command/ query/markup/template and the data on SEPARATE channels so the data has no syntactic power. This single idea covers SQL, XSS, command, LDAP, NoSQL, and template injection. KEEP-DATA-AS-DATA DEFENCE FOR THREE FAMILY MEMBERS: 1. SQL injection -> PARAMETERIZED QUERIES / prepared statements: the query (with placeholders) and the values travel separately; input is bound as data, never parsed as SQL. 2. XSS (browser) -> CONTEXT-AWARE OUTPUT ENCODING (+ CSP): encode input for its output context so it renders as text, not executable markup; sanitize with an allowlist if HTML must be allowed. 3. OS command injection (shell) -> AVOID THE SHELL; pass arguments as an ARRAY (execFile("ping",["-c","1",host])): the binary + fixed flags are the command, the input is a data argument the shell never re-parses. (Also: LDAP/NoSQL -> safe/parameterized APIs + type validation + escape filter metacharacters; SSTI -> render input as DATA into a fixed template, never as a template.) Supporting defence in depth (all members): allowlist input validation, least privilege (limits blast radius — e.g. command injection on a low-priv account), and avoiding dangerous sinks entirely (don't call the shell/eval if a safe library exists). ONE-LINE TAKEAWAY: A03 dropped to #3 and swallowed XSS because frameworks made safe defaults common, not because injection is solved; every family member is one bug — input parsed as code — fixed by one principle: keep data off the code channel.