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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions