Embed Flask security recommendations inline instead of relying on URL fetching at runtime. Add structured sections for resource limits, XSS, CSRF, security headers, CSP, cookies, secrets, CORS, host validation, and additional checks. Include a grading rubric for audit summaries.
7.1 KiB
Flask Security Audit
Perform a security audit of this Flask (or Quart) application. Work through each section below, report findings, and fix issues. At the end, provide a summary with a letter grade for each area.
Instructions
- Audit the project against every section below.
- For each section, report: what is already correct, what needs fixing, and what is not applicable.
- Fix all issues you find. If a fix would be disruptive or ambiguous, describe the fix and ask before applying it.
- At the end, produce a Security Audit Summary table with a letter grade (A-F) for each section.
1. Resource Limits (DoS Prevention)
Verify these Flask config values are set explicitly (not left at defaults):
app.config['MAX_CONTENT_LENGTH'] = <appropriate_limit> # e.g. 16 * 1024 * 1024 for 16MB
app.config['MAX_FORM_MEMORY_SIZE'] = <appropriate_limit> # default 500kB
app.config['MAX_FORM_PARTS'] = <appropriate_limit> # default 1000
MAX_CONTENT_LENGTHhas no default — it must be set.- Consider the app's actual needs when choosing values.
2. Cross-Site Scripting (XSS)
Check for these common XSS pitfalls:
- Unquoted HTML attributes — all template attributes must be quoted:
<input value="{{ value }}">, never<input value={{ value }}>. Markup()on user input — never callMarkup()or|safeon user-submitted data.- HTML generated outside Jinja — any HTML built in Python code must be escaped.
- Uploaded files served as HTML — uploaded files should be served with
Content-Disposition: attachmentor stored with validated content types. javascript:URIs — if anyhreforsrcattribute uses a user-controlled value, validate that it starts withhttp://,https://, or/. Enforce via CSP as well.
3. Cross-Site Request Forgery (CSRF)
Flask has no built-in CSRF protection. Verify that:
- A CSRF library is in use (e.g. Flask-WTF's
CSRFProtect, or equivalent). - All state-changing forms include CSRF tokens.
- AJAX state-changing requests include CSRF tokens in headers.
- If no CSRF protection exists, add it using Flask-WTF:
from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
...
</form>
4. Security Headers
Check that the following response headers are set. Recommend Flask-Talisman if headers are missing or manually managed:
| Header | Required Value |
|---|---|
Strict-Transport-Security |
max-age=31536000; includeSubDomains |
Content-Security-Policy |
See Section 5 below |
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY or SAMEORIGIN |
If Flask-Talisman is not in use, suggest adding it:
from flask_talisman import Talisman
Talisman(app, content_security_policy=csp)
5. Content Security Policy (CSP)
Audit the CSP and make it as restrictive as possible. Apply these principles:
- Start from
default-src 'self'and only open directives that the app actually needs. - Never allow
unsafe-inlineforscript-srcunless absolutely unavoidable. Prefer nonces or hashes. - Never allow
unsafe-evalforscript-src. - Avoid wildcard (
*) origins — list specific domains. - Set
form-action 'self'to prevent form hijacking. - Set
frame-ancestors 'none'(or'self') to prevent clickjacking (replaces X-Frame-Options). - Set
base-uri 'self'to prevent base tag hijacking. - Set
object-src 'none'to block plugins.
Provide:
- The current CSP (or note its absence).
- A recommended CSP with explanations for each directive.
- A letter grade (A-F) assessing how restrictive the CSP is.
6. Cookie and Session Security
Verify these session/cookie configuration values:
app.config.update(
SESSION_COOKIE_SECURE=True, # cookies sent over HTTPS only
SESSION_COOKIE_HTTPONLY=True, # no JavaScript access to session cookie
SESSION_COOKIE_SAMESITE='Lax', # CSRF protection for cookies
PERMANENT_SESSION_LIFETIME=600, # session timeout in seconds
)
Also check:
- Any manually set cookies (
response.set_cookie(...)) should usesecure=True,httponly=True, andsamesite='Lax'. - Sessions are cleared on login (
session.clear()before setting new session data). SECRET_KEYis cryptographically random and not hardcoded (see Section 7).
7. Secrets Management
Verify that:
- No secrets are hardcoded in source files. Search for:
SECRET_KEY,PASSWORD,API_KEY,TOKEN, database URIs with credentials, and similar patterns. - All secrets are loaded from environment variables.
- A
.envfile exists for local development, and.envis listed in.gitignore. - Use
python-dotenvto load the.envfile:
from dotenv import load_dotenv
load_dotenv()
app.config['SECRET_KEY'] = os.environ['SECRET_KEY']
- Create
.gitignoreif it does not exist. Ensure.envis in it. - If a
.env.examplefile does not exist, create one with placeholder values (never real secrets).
8. CORS Configuration
If CORS is configured (e.g. via Flask-CORS), review and explain:
- Which origins are allowed. Flag
*(allow-all) as a problem unless this is a fully public API. - Which methods and headers are allowed.
- Whether
supports_credentials=Trueis set — this is dangerous with broad origins. - If CORS is not needed, confirm it is not enabled.
9. Host Header Validation
Check that trusted hosts are configured to prevent host header poisoning:
app.config['TRUSTED_HOSTS'] = ['example.com', 'www.example.com']
If the app runs behind a reverse proxy, verify ProxyFix is configured correctly:
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
10. Additional Checks
- Debug mode: Verify
app.debugisFalseandFLASK_DEBUGis not set to1in production config. - JSON security: If the app returns JSON arrays at top level, confirm this is intentional.
- File uploads: If file uploads exist, verify filenames are sanitized with
werkzeug.utils.secure_filename(). - SQL injection: If raw SQL is used, verify parameterized queries. Flag any string concatenation/formatting in SQL.
- Dependency vulnerabilities: Run
pip auditorsafety checkif available and report results.
Security Audit Summary
After completing all sections, produce a summary in this format:
| Section | Grade | Notes |
|---|---|---|
| 1. Resource Limits | ? | |
| 2. XSS Prevention | ? | |
| 3. CSRF Protection | ? | |
| 4. Security Headers | ? | |
| 5. Content Security Policy | ? | |
| 6. Cookie/Session Security | ? | |
| 7. Secrets Management | ? | |
| 8. CORS Configuration | ? | |
| 9. Host Header Validation | ? | |
| 10. Additional Checks | ? | |
| Overall | ? |
Grading scale:
- A: Best practices fully implemented
- B: Mostly good, minor improvements possible
- C: Functional but missing important protections
- D: Significant security gaps
- F: Critical vulnerabilities present