Topic 10 · Deep Dive

10.2 Input Forms, File Uploads, and Simple Injection Ideas

Untrusted Input Is a Language Problem

Injection is not exotic malware; it is a syntax accident. Every field a user can type -- search boxes, profile bio text, headers, filename parameters, JSON values -- arrives as bytes that the server later pastes into some interpreter: SQL, a shell command, a template, an LDAP filter, an HTML page. The program intends those bytes to be data; the interpreter, fooled by structure characters like quotes or semicolons, reads them as instructions. The fix is never to sanitize cleverly, it is to keep data and code on separate channels so structure characters stop mattering.

Concatenation Is the Vulnerability

Watch what happens when a query is built with string concatenation. The developer writes something like SELECT * FROM users WHERE name = ' and appends the submitted value, then closes the quote. Type alice and the statement is boring. Type ' OR '1'='1 instead and the first character closes the developer's quote, the middle becomes a condition that is true for every row, and the tail quote is absorbed as a comment or balanced pair. The attacker did not attack the database -- they finished the developer's sentence. Variants stack: UNION SELECT pulls other tables into the response, stacked statements can write files where the dialect allows it, and blind variants infer data one yes-or-no question at a time through timing or error behavior. The OWASP Top Ten lists injection as a permanent class precisely because concatenation keeps reappearing in new frameworks.

File Uploads and the Extension Lie

Uploads are injection with a filename. A box that accepts "any document" and stores it under its original name inside the web root turns a request into remote execution the moment someone requests shell.php. Content-Type is client-supplied theater; magic bytes can be faked in the first kilobyte; so the durable controls are an extension allowlist, a generated random filename, a stored path outside the document root or on separate storage, no execute bit, and image re-encoding that destroys embedded payloads. Add path traversal on the name -- ../../ segments -- and one unchecked field escapes its own directory.

Closing the Class of Bug

Parameterized queries with bound arguments make SQLi structurally impossible; allowlist validation beats denylist pattern matching; context-aware output encoding neutralizes reflected HTML; shells get invoked with argument arrays rather than concatenated strings. The OWASP Testing Guide and the OWASP Cheat Sheet Series organize exactly these controls by interpreter, because every layer that eats strings needs a boundary.

Architecture Diagram

injection and upload paths request untrusted body raw field value no allowlist check WHERE name = ' string concat ' OR '1'='1 closes the quote DB upload box name, type, size unchecked server-executed extension .php .jsp .asp exec on server or path traversal fix: bound parameters, allowlist extensions, store outside webroot, clear exec bit
Two ordinary features -- a text field and an upload -- become code execution once user bytes reach an interpreter or an executable directory.

Key Takeaways

« Back to Topic 10« 10.1 / 10.3 »