Skip to main content

Flask extension that masks 404 responses to reduce directory fuzzing signal quality.

Project description

Flask AntiFuzz

Flask AntiFuzz is a simple Flask extension that reduces the usefulness of directory fuzzing signals by masking 404 Not Found responses as normal-looking HTML responses with variable hidden padding.

This extension can be considered a protection against directory fuzzing aimed at identifying sensitive and insecure endpoints. It will also help mitigate certain types of credential stuffing attacks, when an attacker targets noticeable variations in the server response size and other scenarios where the size of the server response is important.

From the attacker's side (example): изображение

Installation

pip install flask-antifuzz

Usage

from flask import Flask
from flask_antifuzz import Antifuzz

app = Flask(__name__)
antifuzz = Antifuzz(app)

The extension also supports the app factory pattern:

from flask import Flask
from flask_antifuzz import Antifuzz

antifuzz = Antifuzz()


def create_app():
    app = Flask(__name__)
    antifuzz.init_app(app)
    return app

Demo Applications

The repository includes two small Flask applications for comparison:

Path Purpose
app/ Protected demo application with Antifuzz(app) enabled.
fuzzed/app/ Intentionally unprotected baseline application for directory-fuzzing comparisons.

The fuzzed/app/ service is kept in git on purpose. It is not included in the published wheel.

Configuration

Set values on app.config before initializing the extension.

Key Default Description
ANTIFUZZ_ENABLED True Enables or disables the 404 masking handler.
ANTIFUZZ_STATUS_CODE 200 Status code returned for missing paths while enabled.
ANTIFUZZ_MIN_RESPONSE_BYTES None Manual minimum target response size. Must be set with ANTIFUZZ_MAX_RESPONSE_BYTES.
ANTIFUZZ_MAX_RESPONSE_BYTES None Manual maximum target response size. Must be set with ANTIFUZZ_MIN_RESPONSE_BYTES.
ANTIFUZZ_AUTO_SIZE_ENABLED True Automatically derives response size bounds from template/static HTML-like files.
ANTIFUZZ_FALLBACK_MIN_RESPONSE_BYTES 6144 Minimum target response size when auto sizing finds no files.
ANTIFUZZ_FALLBACK_MAX_RESPONSE_BYTES 163840 Maximum target response size when auto sizing finds no files.
ANTIFUZZ_SIZE_MARGIN_RATIO 0.25 Extra proportional size margin added around discovered file sizes.
ANTIFUZZ_SIZE_MIN_MARGIN_BYTES 512 Minimum byte margin added around discovered file sizes.
ANTIFUZZ_SIZE_FILE_EXTENSIONS (".html", ".htm", ".jinja", ".jinja2", ".j2") File extensions used for auto sizing.
ANTIFUZZ_PAD_ALL_HTML_RESPONSES True Adds the same hidden padding shape to normal HTML responses.
ANTIFUZZ_MIN_PADDING_BYTES 96 Minimum hidden padding added to each padded HTML response.
ANTIFUZZ_RAND_404_TITLE False Randomizes the <title> value on masked 404 HTML responses.
ANTIFUZZ_404_TITLE_MIN_LENGTH 5 Minimum randomized 404 title length.
ANTIFUZZ_404_TITLE_MAX_LENGTH 10 Maximum randomized 404 title length.
ANTIFUZZ_RENDERER None Optional callable for an explicit extension-managed 404 response.

Response Sizing

You do not need to configure response sizes for a typical Flask app. Manual size settings default to None, so AntiFuzz starts in auto-sizing mode.

By default, AntiFuzz scans the Flask application's configured template_folder and static_folder during initialization. It looks for HTML/Jinja-like files, measures their source file sizes, then adds a safety margin to build the random response-size range used for masked 404 responses.

The configured size range is a final response-size target, not the amount of padding to add. AntiFuzz subtracts the current HTML body size before adding padding. If the response is already above the maximum, or if there is not enough remaining room for the hidden block, it leaves the body unchanged instead of growing the response past the configured maximum.

Manual sizing takes priority over auto sizing:

app.config["ANTIFUZZ_MIN_RESPONSE_BYTES"] = 3000
app.config["ANTIFUZZ_MAX_RESPONSE_BYTES"] = 9000
Antifuzz(app)

Use manual sizing for highly dynamic pages where rendered HTML is much larger than the source Jinja template.

The fallback range is based on HTTP Archive's 2025 Web Almanac HTML response size distribution: common HTML responses cluster around a 33-35 KB median, with the 90th percentile around 148-155 KB.

Padding Placement

AntiFuzz pads all non-streamed text/html responses by default, not only 404 responses. This keeps the defensive page from being identifiable by the mere presence of hidden padding.

The padding is inserted immediately before </body>. If a response has no closing body tag, the padding is appended to the end of the response. The block is a plain hidden div with text-like random payload and does not include any project-specific signatures.

404 Handling

AntiFuzz does not replace your application's 404 page. Flask or your own @app.errorhandler(404) still creates the response body. AntiFuzz then changes the response status from 404 to ANTIFUZZ_STATUS_CODE and applies the same HTML padding layer used for normal pages.

If ANTIFUZZ_RAND_404_TITLE is enabled, AntiFuzz also replaces the 404 page's <title> value with a random ASCII title. If the page has a <head> but no <title>, AntiFuzz inserts one.

Custom Responses

Prefer Flask's normal error-handler API for application-owned 404 pages:

@app.errorhandler(404)
def not_found(error):
    return render_template("error404.html"), 404

AntiFuzz will keep that body, change the status code, and apply padding. Use ANTIFUZZ_RENDERER only when you explicitly want the extension to own 404 rendering:

from flask import render_template


def antifuzz_renderer(error):
    return render_template("error404.html"), 200


app.config["ANTIFUZZ_RENDERER"] = antifuzz_renderer
Antifuzz(app)

Development and testing

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e ".[test]"
python -m pytest

Build and validate package artifacts:

python -m pip install build twine
python -m build
python -m twine check dist/*

Run the demo applications:

flask --app app/main.py run --port 5000
flask --app fuzzed/app/main.py run --port 5001

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flask_antifuzz-0.1.0.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flask_antifuzz-0.1.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file flask_antifuzz-0.1.0.tar.gz.

File metadata

  • Download URL: flask_antifuzz-0.1.0.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for flask_antifuzz-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8548c630f34de552324c2d48713028b6def58523249cdf0c0ead36fd065e2449
MD5 9f241116f71abe8c80b5044a2c10f716
BLAKE2b-256 aaf5d20f2ed02c32fa4877c21f8fbc7addb3465564b36811c1f7590c30db538a

See more details on using hashes here.

File details

Details for the file flask_antifuzz-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: flask_antifuzz-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for flask_antifuzz-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7955040bd4603743d89b8b9ece43a8ec1542db1737889b44531669bf709d4457
MD5 c4d57500b466ebaf384ea954d8799078
BLAKE2b-256 6b2af0189d0eb8e565cc64ba01c94e29b2fbcdee0bc7621cd58bcc7c4c5e04f7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page