Flask gives you a lot of flexibility—but input validation is often an afterthought.
In my day job, I work in application security across architecture, engineering, and operations. A big part of what my team does is helping development teams fix findings from SAST/DAST scans and code reviews.
And one issue comes up over and over:
Unvalidated input making its way into application logic.
⸻
The gap I keep seeing
When working with Flask applications, there are great options:
- Flask-WTF for full UI apps
- Marshmallow or Pydantic for APIs
But in practice, many applications don’t use either.
I did a quick Google search and was surprised to see estimates suggesting 50–80% of Flask apps don’t use a validation framework at all. From what I’ve seen in real environments, that doesn’t feel far off.
Instead, I typically find:
- ad hoc validation scattered across routes
- inconsistent handling of input
- or no validation at all
⸻
Why this matters (from a security perspective)
This isn’t just about clean code.
It leads directly to:
- injection risks
- unexpected behavior
- inconsistent error handling
- findings in SAST/DAST that are hard to fix systematically
And more importantly:
It becomes very hard to answer: “What is actually protected?”
⸻
So I built something small
I wanted something that:
- didn’t require forms
- didn’t require full schema frameworks
- was easy to drop into existing apps
- enforced consistency
- and (this part matters) could detect what’s missing
So I built a small decorator-based validation library:
👉 https://github.com/blainekwilson/flask-validate
⸻
Example usage:
`from flask import Flask, request
import flask_validate as fv
app = Flask(name)
@app.route("/submit", methods=["POST"])
@fv.validate({
"args": {
"st": {"required": True, "rules": fv.US_STATE}
},
"form": {
"zip": {"required": False, "rules": fv.US_ZIP}
}
})
def submit():
return f"State: {request.args['st']}"`
Simple, but structured
Validation is:
- explicit
- centralized
- reusable
Errors are returned per field:
{
"errors": {
"zip": ["Invalid ZIP code"],
"st": ["Invalid US state"]
}
}
And you can fully control the response:
`def json_error_handler(result):
return {"errors": result["errors"]}, 400
@fv.validate(schema, on_error=json_error_handler)
def route():
...`
The part I haven’t seen elsewhere
The feature I care about most isn’t validation itself.
It’s this:
Detecting routes that are missing validation entirely
You can run:
python -m flask_validate app:app
And get a report of:
- protected routes
- excluded routes
- unprotected routes (with priority levels)
This has been surprisingly useful in practice.
Instead of asking:
“Did we validate this input?”
You can ask:
“Which endpoints are not validated at all?”
⸻
When this makes sense (and when it doesn’t)
This isn’t meant to replace existing tools.
Use:
- Flask-WTF for complex UI apps
- Pydantic / Marshmallow for APIs
This is for the middle ground:
- simple Flask apps
- internal tools
- lightweight UIs
⸻
What I’m looking for
I think this is useful—but I also know there are people far deeper into Flask and Python than I am.
Before I push this to PyPI, I’d really value feedback on:
- Is this solving a real problem?
- Am I missing something obvious?
- Is the decorator approach the right abstraction?
- Are there better ways to handle this space?
⸻
Final thought
A lot of security issues aren’t caused by lack of knowledge—they’re caused by lack of structure.
I’m trying to make the “secure path” a little easier to follow for simple Flask apps.
Top comments (0)