Flask-Talisman and Reverse Proxy Configuration#
Superset uses Flask-Talisman to enforce HTTP security headers and Content Security Policy (CSP). The Talisman instance is declared as a module-level extension and initialized conditionally during app startup.
Talisman is disabled by default. It must be explicitly enabled for production deployments .
Key Configuration Variables#
All settings live in superset/config.py and can be overridden via superset_config.py .
| Variable | Default | Purpose |
|---|---|---|
TALISMAN_ENABLED | False | Enable/disable Talisman. Also settable via TALISMAN_ENABLED env var. |
TALISMAN_CONFIG | (see below) | Kwargs passed to talisman.init_app() in production/non-debug mode. |
TALISMAN_DEV_CONFIG | (see below) | Used when app.debug=True; relaxes CSP to allow React's unsafe-eval. |
CONTENT_SECURITY_POLICY_WARNING | True | Logs a warning at startup if no CSP is configured in non-debug mode. |
ENABLE_PROXY_FIX | False | Enables Werkzeug's ProxyFix middleware for X-Forwarded-* headers. |
PROXY_FIX_CONFIG | {x_for:1, x_proto:1, x_host:1, x_port:1, x_prefix:1} | Trusted proxy hop counts for each forwarded header. |
Initialization Flow#
Talisman and ProxyFix are both configured inside configure_middlewares() in superset/initialization/__init__.py.
The sequence within that method:
- ProxyFix is applied first (if
ENABLE_PROXY_FIX=True), wrapping the WSGI app . - Talisman config is selected:
TALISMAN_DEV_CONFIGis used whenapp.debugorconfig["DEBUG"]isTrue; otherwiseTALISMAN_CONFIG. - Talisman is initialized via
talisman.init_app(self.superset_app, **talisman_config)if enabled . - CSP warning is emitted at startup if Talisman is disabled or has no
content_security_policydefined in non-debug mode .
Default TALISMAN_CONFIG#
The default TALISMAN_CONFIG ships with a production-ready CSP and with HTTPS enforcement deliberately turned off:
content_security_policy: restrictsscript-srcto'self'+'strict-dynamic',object-srcto'none', and allowsimg-srcfor blob/data URIs plus a few CDN domains (Scarf, Document360, OpenStreetMap tile servers).content_security_policy_nonce_in: ["script-src"]: Talisman automatically injects a per-request nonce into<script>tags and thescript-srcheader.force_https: False: HTTPS is not enforced at the app level (see Reverse Proxy Setup below).session_cookie_secure: False: cookies are not restricted to HTTPS-only connections at the Talisman level.
The dev config (TALISMAN_DEV_CONFIG) is identical except script-src also allows 'unsafe-inline' and 'unsafe-eval' for React's hot-reload mode.
Slack avatars: if
SLACK_ENABLE_AVATARSis enabled, addhttps://avatars.slack-edge.comtoimg-srcin your customTALISMAN_CONFIG.
Reverse Proxy Setup (TLS Termination)#
When Superset runs behind a reverse proxy (nginx, Traefik, etc.) that terminates TLS, the app receives plain HTTP internally. This requires coordinating several settings.
1. Enable ProxyFix#
Set ENABLE_PROXY_FIX = True so Flask reconstructs the correct scheme, host, and client IP from X-Forwarded-* headers . The default PROXY_FIX_CONFIG trusts one hop for each header; adjust counts to match your proxy chain depth .
2. Keep force_https: False#
Do not set force_https: True when a proxy terminates TLS. Superset receives HTTP from the proxy; Talisman would redirect those HTTP requests back to HTTPS, creating redirect loops or breaking internal service-to-service calls. This directly affects Celery workers for Alerts/Reports — they call WEBDRIVER_BASEURL over HTTP internally, and a forced redirect causes those tasks to fail . The proxy itself should enforce HTTPS for external traffic.
3. Coordinate session_cookie_secure with Internal HTTP#
The SESSION_COOKIE_SECURE flag (default False) controls whether session cookies are sent only over HTTPS. When True, cookies are silently dropped on HTTP connections — including internal Celery worker calls that use WEBDRIVER_BASEURL = "http://...". The practical result is that CSV report generation returns HTTP 500 because the internal request arrives unauthenticated .
Choose one approach:
- Set
SESSION_COOKIE_SECURE = Falseif workers and the app server communicate over a trusted internal network (Docker network, etc.). External users still see HTTPS through the proxy. - Or change
WEBDRIVER_BASEURLto an internal HTTPS endpoint and terminate TLS for internal traffic too.
4. Separate internal vs. user-facing URLs#
Superset has two relevant URL settings :
| Setting | Purpose |
|---|---|
WEBDRIVER_BASEURL | Internal URL used by Celery workers/webdrivers. Should use HTTP if TLS is terminated at the proxy. |
WEBDRIVER_BASEURL_USER_FRIENDLY | External HTTPS URL used in email/notification links shown to users. |
CSP Customization#
Override TALISMAN_CONFIG in superset_config.py to extend or modify the CSP. The config comment points to the official networking settings docs for further guidance.
Common additions:
-
iframe embedding: add a
frame-ancestorsdirective to allow Superset to be embedded in other origins:"frame-ancestors": ["'self'", "https://your-app.example.com"] -
Slack avatars: add
https://avatars.slack-edge.comtoimg-srcwhenSLACK_ENABLE_AVATARSis enabled . -
Mapbox:
connect-srcalready includeshttps://api.mapbox.comandhttps://events.mapbox.comby default . -
Custom fonts/styles: add domains to
style-srcandfont-srcas needed.
When TALISMAN_ENABLED = False (the default), Superset logs a startup warning urging you to configure CSP via an alternative mechanism .