Skip to content

CSRF default-on decision (5.0): flip the default after the detect-and-warn deprecation window #2960

Description

@bpamiri

Problem

CSRF protection is opt-in and silently disabled by the documented config() override footgun. vendor/wheels/controller/csrf.cfc:18-20, 37-51 no-ops unless StructKeyExists(variables.$class, "csrf"); CSRF is wired only via the generated base controller (cli/lucli/templates/app/app/controllers/Controller.cfc:23-25), which itself doesn't call super.config(). Any child controller overriding config() without super.config() silently disables CSRF for that controller, with no error or startup warning. Verified against origin/develop @ 8971094.

This is a recurring footgun (tracked around #2845; see also project memory on the super.config() chain fragility). Prior remediation chose docs + generator templates that call super.config().

Impact

A developer who overrides config() in a controller — a common, documented pattern — without calling super.config() silently ships that controller with CSRF disabled and no warning. The protection's presence is invisible and easy to drop.

Suggested approach

This is a deliberate behavior change for every existing app, so it needs an upgrade-path design rather than an autonomous flip:

  • Either enforce CSRF at the dispatch/middleware layer (independent of per-controller config()), or
  • Detect-and-warn at startup when a controller overrides config() without calling super.config().
  • If making CSRF default-on, design a deprecation window / upgrade note so existing apps are not broken silently.

Acceptance criteria

  • A controller overriding config() without super.config() either keeps CSRF active or emits a clear startup/dev warning.
  • If the default flips on, an upgrade path and wheels upgrade check advisory exist.
  • Specs cover the override-without-super.config() case.

Source

Internal multi-agent framework review 2026-06-09, wave 2 (issues phase). Findings: security-pass SEC-10 (S5), followups SEC-10.

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingdesign-decisionParked pending an explicit maintainer design decisionv5.0Deferred to the 5.0 major (often breaking)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions