# 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): ```python app.config['MAX_CONTENT_LENGTH'] = # e.g. 16 * 1024 * 1024 for 16MB app.config['MAX_FORM_MEMORY_SIZE'] = # default 500kB app.config['MAX_FORM_PARTS'] = # default 1000 ``` - `MAX_CONTENT_LENGTH` has 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: ``, never ``. - **`Markup()` on user input** — never call `Markup()` or `|safe` on 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: attachment` or stored with validated content types. - **`javascript:` URIs** — if any `href` or `src` attribute uses a user-controlled value, validate that it starts with `http://`, `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: ```python from flask_wtf.csrf import CSRFProtect csrf = CSRFProtect(app) ``` ```html
...
``` --- ## 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: ```python 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-inline` for `script-src` unless absolutely unavoidable. Prefer nonces or hashes. - **Never allow** `unsafe-eval` for `script-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: 1. The current CSP (or note its absence). 2. A recommended CSP with explanations for each directive. 3. A letter grade (A-F) assessing how restrictive the CSP is. --- ## 6. Cookie and Session Security Verify these session/cookie configuration values: ```python 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 use `secure=True`, `httponly=True`, and `samesite='Lax'`. - Sessions are cleared on login (`session.clear()` before setting new session data). - `SECRET_KEY` is 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 `.env` file exists for local development, and `.env` is listed in `.gitignore`. - Use `python-dotenv` to load the `.env` file: ```python from dotenv import load_dotenv load_dotenv() app.config['SECRET_KEY'] = os.environ['SECRET_KEY'] ``` - Create `.gitignore` if it does not exist. Ensure `.env` is in it. - If a `.env.example` file 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=True` is 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: ```python app.config['TRUSTED_HOSTS'] = ['example.com', 'www.example.com'] ``` If the app runs behind a reverse proxy, verify `ProxyFix` is configured correctly: ```python 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.debug` is `False` and `FLASK_DEBUG` is not set to `1` in 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 audit` or `safety check` if 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