Flask Request
In Flask, the request object gives you access to all incoming request data sent by the client like form inputs, JSON payloads, headers, cookies, and more.
Accessing Form Data
For POST requests with application/x-www-form-urlencoded or multipart/form-data.
from flask import request
@app.route('/submit', methods=['POST'])
def submit():
username = request.form['username']
return f"Hello, {username}"
For POST requests with application/json
@app.route('/api', methods=['POST'])
def api():
data = request.get_json()
return {'you_sent': data}
For GET requests with query string parameters
@app.route('/greet')
def greet():
name = request.args.get('name', 'Guest')
return f"Hello, {name}"
Access Headers
@app.route('/info')
def info():
agent = request.headers.get('User-Agent')
return f"You're using: {agent}"
Why the request object matters from an offensive security perspective
The request object is the trust boundary. Everything reachable through it, request.form, request.args, request.get_json(), request.headers, request.cookies, request.files, the path, is attacker-controlled. The client sends it, so the client chooses it. There is no such thing as a “safe” field on request; a User-Agent is as forgeable as a form value, and a header an app trusts (X-Forwarded-For, a role header) is a header an attacker sets.
When you audit, every request.* read is a taint source. The bug is whatever sink that tainted value reaches without validation:
f"Hello, {request.args.get('name')}"rendered as a template is SSTI.- A
requestvalue passed tosubprocess/os.systemis command injection. - Concatenated into a SQL query, it is SQLi.
- Used as a filename or path, it is path traversal.
- Handed to
pickle.loads/yaml.load, it is insecure deserialization.
Notice the examples on this page already concatenate request data straight into the response with f-strings. That pattern, request data flowing into a sink with no validation in between, is the shape of nearly every vulnerability in this handbook. The methodology is always the same: find the source (request), trace it to the sink, and confirm nothing sanitizes it along the way.
Mitigation
Treat every request.* read as untrusted and validate it at the point of use against the contract the sink expects, then let the sink’s safe API do the encoding rather than building strings by hand. Coerce types explicitly (int(request.args.get("id"))), constrain values to an allowlist where the set is known, and never hand raw request data to a template source, a shell, a SQL string, or a deserializer. Return data through render_template and parameterized queries so escaping happens for you instead of relying on manual sanitization.
from flask import request, render_template, abort
@app.route("/greet")
def greet():
name = request.args.get("name", "Guest")
if not name.isalnum(): # validate against the expected shape
abort(400)
return render_template("greet.html", name=name) # autoescaped, name is data not template