<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Blaine Wilson</title>
    <description>The latest articles on DEV Community by Blaine Wilson (@blaine_wils_45095dc2c68f6).</description>
    <link>https://dev.to/blaine_wils_45095dc2c68f6</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3899208%2Ff840a429-d5c8-4a9d-8a7b-f07bda8d8573.jpeg</url>
      <title>DEV Community: Blaine Wilson</title>
      <link>https://dev.to/blaine_wils_45095dc2c68f6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/blaine_wils_45095dc2c68f6"/>
    <language>en</language>
    <item>
      <title>Most Flask Apps Miss This: Auditable Input Validation &amp; Detecting Unvalidated Routes</title>
      <dc:creator>Blaine Wilson</dc:creator>
      <pubDate>Mon, 27 Apr 2026 01:25:43 +0000</pubDate>
      <link>https://dev.to/blaine_wils_45095dc2c68f6/most-flask-apps-miss-this-auditable-input-validation-detecting-unvalidated-routes-5cjp</link>
      <guid>https://dev.to/blaine_wils_45095dc2c68f6/most-flask-apps-miss-this-auditable-input-validation-detecting-unvalidated-routes-5cjp</guid>
      <description>&lt;p&gt;Flask gives you a lot of flexibility—but input validation is often an afterthought.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;And one issue comes up over and over:&lt;/p&gt;

&lt;p&gt;Unvalidated input making its way into application logic.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;The gap I keep seeing&lt;/p&gt;

&lt;p&gt;When working with Flask applications, there are great options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flask-WTF for full UI apps&lt;/li&gt;
&lt;li&gt;Marshmallow or Pydantic for APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But in practice, many applications don’t use either.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Instead, I typically find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ad hoc validation scattered across routes&lt;/li&gt;
&lt;li&gt;inconsistent handling of input&lt;/li&gt;
&lt;li&gt;or no validation at all&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Why this matters (from a security perspective)&lt;/p&gt;

&lt;p&gt;This isn’t just about clean code.&lt;/p&gt;

&lt;p&gt;It leads directly to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;injection risks&lt;/li&gt;
&lt;li&gt;unexpected behavior&lt;/li&gt;
&lt;li&gt;inconsistent error handling&lt;/li&gt;
&lt;li&gt;findings in SAST/DAST that are hard to fix systematically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And more importantly:&lt;/p&gt;

&lt;p&gt;It becomes very hard to answer: “What is actually protected?”&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;So I built something small&lt;/p&gt;

&lt;p&gt;I wanted something that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;didn’t require forms&lt;/li&gt;
&lt;li&gt;didn’t require full schema frameworks&lt;/li&gt;
&lt;li&gt;was easy to drop into existing apps&lt;/li&gt;
&lt;li&gt;enforced consistency&lt;/li&gt;
&lt;li&gt;and (this part matters) could detect what’s missing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built a small decorator-based validation library:&lt;br&gt;
👉 &lt;a href="https://github.com/blainekwilson/flask-validate" rel="noopener noreferrer"&gt;https://github.com/blainekwilson/flask-validate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Example usage:&lt;br&gt;
`from flask import Flask, request&lt;br&gt;
import flask_validate as fv&lt;/p&gt;

&lt;p&gt;app = Flask(&lt;strong&gt;name&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;@app.route("/submit", methods=["POST"])&lt;br&gt;
@fv.validate({&lt;br&gt;
    "args": {&lt;br&gt;
        "st": {"required": True, "rules": fv.US_STATE}&lt;br&gt;
    },&lt;br&gt;
    "form": {&lt;br&gt;
        "zip": {"required": False, "rules": fv.US_ZIP}&lt;br&gt;
    }&lt;br&gt;
})&lt;br&gt;
def submit():&lt;br&gt;
    return f"State: {request.args['st']}"`&lt;/p&gt;

&lt;p&gt;Simple, but structured&lt;/p&gt;

&lt;p&gt;Validation is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;explicit&lt;/li&gt;
&lt;li&gt;centralized&lt;/li&gt;
&lt;li&gt;reusable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Errors are returned per field:&lt;br&gt;
&lt;code&gt;{&lt;br&gt;
  "errors": {&lt;br&gt;
    "zip": ["Invalid ZIP code"],&lt;br&gt;
    "st": ["Invalid US state"]&lt;br&gt;
  }&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And you can fully control the response:&lt;br&gt;
`def json_error_handler(result):&lt;br&gt;
    return {"errors": result["errors"]}, 400&lt;/p&gt;

&lt;p&gt;@fv.validate(schema, on_error=json_error_handler)&lt;br&gt;
def route():&lt;br&gt;
    ...`&lt;/p&gt;

&lt;p&gt;The part I haven’t seen elsewhere&lt;/p&gt;

&lt;p&gt;The feature I care about most isn’t validation itself.&lt;/p&gt;

&lt;p&gt;It’s this:&lt;/p&gt;

&lt;p&gt;Detecting routes that are missing validation entirely&lt;/p&gt;

&lt;p&gt;You can run:&lt;br&gt;
&lt;code&gt;python -m flask_validate app:app&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And get a report of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;protected routes&lt;/li&gt;
&lt;li&gt;excluded routes&lt;/li&gt;
&lt;li&gt;unprotected routes (with priority levels)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This has been surprisingly useful in practice.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;p&gt;“Did we validate this input?”&lt;/p&gt;

&lt;p&gt;You can ask:&lt;/p&gt;

&lt;p&gt;“Which endpoints are not validated at all?”&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;When this makes sense (and when it doesn’t)&lt;/p&gt;

&lt;p&gt;This isn’t meant to replace existing tools.&lt;/p&gt;

&lt;p&gt;Use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flask-WTF for complex UI apps&lt;/li&gt;
&lt;li&gt;Pydantic / Marshmallow for APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is for the middle ground:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simple Flask apps&lt;/li&gt;
&lt;li&gt;internal tools&lt;/li&gt;
&lt;li&gt;lightweight UIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;What I’m looking for&lt;/p&gt;

&lt;p&gt;I think this is useful—but I also know there are people far deeper into Flask and Python than I am.&lt;/p&gt;

&lt;p&gt;Before I push this to PyPI, I’d really value feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this solving a real problem?&lt;/li&gt;
&lt;li&gt;Am I missing something obvious?&lt;/li&gt;
&lt;li&gt;Is the decorator approach the right abstraction?&lt;/li&gt;
&lt;li&gt;Are there better ways to handle this space?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Final thought&lt;/p&gt;

&lt;p&gt;A lot of security issues aren’t caused by lack of knowledge—they’re caused by lack of structure.&lt;/p&gt;

&lt;p&gt;I’m trying to make the “secure path” a little easier to follow for simple Flask apps.&lt;/p&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>security</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
