Typorithm · medium

Flask: trusted hosts and production deployment boundaries

pythonflaskindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

Flask: trusted hosts and production deployment boundaries

0%

Concept and contract

Use current host validation and understand what a local client cannot prove.

An application may use the request host for redirects, external URLs or security-sensitive decisions. Treat that value as untrusted unless the deployment enforces an explicit host policy.

Flask 3.1 introduced TRUSTED_HOSTS for host validation. SERVER_NAME has other URL-generation and routing roles and should not be mistaken for a host-security allowlist on current Flask versions.

Mechanism and worked example

The fixture permits trusted.test and sends a real client request with a controlled Host header.

The fixture permits trusted.test and sends a real client request with a controlled Host header. The framework returns 400 for an untrusted host before a normal successful response is accepted.

A host with the expected name and an ordinary port remains within the policy. The test exercises the pinned framework’s validation without changing DNS or opening a public listening socket.

Complete worked example

python

from flask import Flask

def host_status(host):
    app = Flask(__name__)
    app.config.update(TESTING=True, TRUSTED_HOSTS=['trusted.test'])
    @app.get('/health')
    def health():
        return {'ok': True}
    return app.test_client().get('/health', headers={'Host': host}).status_code
Reasoning
The fixture permits trusted.test and sends a real client request with a controlled Host header. The framework returns 400 for an untrusted host before a normal successful response is accepted.

Counterexamples and common mistakes

The counterexample removes TRUSTED_HOSTS and sets SERVER_NAME instead, leaving the unwanted host accepted in this current version..

The counterexample removes TRUSTED_HOSTS and sets SERVER_NAME instead, leaving the unwanted host accepted in this current version.

Another deployment mistake is trusting arbitrary forwarded headers. ProxyFix must be configured only for the known number of trusted proxy hops; blindly accepting client-supplied forwarding data can make generated URLs or client-address policies attacker-controlled.

Counterexample: a runnable framework mistake

python

from flask import Flask

def host_status(host):
    app = Flask(__name__)
    app.config.update(TESTING=True, SERVER_NAME='trusted.test')
    @app.get('/health')
    def health():
        return {'ok': True}
    return app.test_client().get('/health', headers={'Host': host}).status_code
Reasoning
The counterexample removes TRUSTED_HOSTS and sets SERVER_NAME instead, leaving the unwanted host accepted in this current version.

Independent practice: one bounded framework change

Allow preview.test as a second exact trusted host while retaining rejection of unrelated names.

Allow preview.test as a second exact trusted host while retaining rejection of unrelated names. Do not use a wildcard or leading-dot pattern for this task.

Preserve the existing status behavior and demonstrate both accepted names. This small policy extension is safer to reason about than changing proxy topology, transport settings and host generation in one exercise.

Step 1: Add preview.test as a second exact trusted host. Step 2: Extend the explicit allowlist.

Practice starter: solve before reading the solution

python

from flask import Flask

def host_status(host):
    # Remove this placeholder, then adapt the retained baseline:
    # Add preview.test as a second exact trusted host.
    raise NotImplementedError
    app = Flask(__name__)
    app.config.update(TESTING=True, TRUSTED_HOSTS=['trusted.test'])
    @app.get('/health')
    def health():
        return {'ok': True}
    return app.test_client().get('/health', headers={'Host': host}).status_code
Reasoning
Add preview.test as a second exact trusted host. Extend the explicit allowlist.
  • Hint 1: Preserve the original hostname.
  • Hint 2: Keep unrelated hosts rejected.

Solution, tests and trade-offs

Fixtures compare trusted.test, trusted.test with a port and evil.test.

Fixtures compare trusted.test, trusted.test with a port and evil.test. Practice adds preview.test and keeps the negative request.

These are application-level host checks. They do not establish TLS correctness, trusted proxy placement or browser cookie transport settings. Those require separate deployed checks, and a passing local client suite should not be advertised as complete production readiness.

Practice solution and acceptance checks

python

from flask import Flask

def host_status(host):
    app = Flask(__name__)
    app.config.update(TESTING=True, TRUSTED_HOSTS=['trusted.test', 'preview.test'])
    @app.get('/health')
    def health():
        return {'ok': True}
    return app.test_client().get('/health', headers={'Host': host}).status_code
Reasoning
Fixtures compare trusted.test, trusted.test with a port and evil.test. Practice adds preview.test and keeps the negative request.

Interview reasoning and next step

Deploy Flask through a production WSGI server rather than the development server or interactive debugger..

Deploy Flask through a production WSGI server rather than the development server or interactive debugger.

Bound request size, worker count and timeouts according to available capacity, and understand that async views do not automatically turn WSGI into an unbounded background task runtime. Keep secrets out of source and review security changes when upgrading Flask, Werkzeug and extensions together.

Optional stretch — after the core task works: Document a trusted proxy chain and rehearse generated external URLs.

Computer practice: https://applydjinn.com/typorithm/python-frameworks-lab-20261105.zip. Install the pinned dependencies in an isolated environment, run verify.py --track flask, then edit the retained exercise baseline and check it with --practice fl-deployment. The lab uses owned in-memory databases, local framework clients and tiny CPU tensors. It never reads the working ApplyDjinn database, contacts production feeds or downloads models.

Use current host validation and understand what a local client cannot prove.