Skip to content

security: CSRF protection, POST enforcement, cookie allowlist#95

Open
rhoerr wants to merge 5 commits intovpietri:mainfrom
rhoerr:qdb/pr2-csrf-lockdown
Open

security: CSRF protection, POST enforcement, cookie allowlist#95
rhoerr wants to merge 5 commits intovpietri:mainfrom
rhoerr:qdb/pr2-csrf-lockdown

Conversation

@rhoerr
Copy link
Copy Markdown

@rhoerr rhoerr commented Apr 5, 2026

Summary

  • Implement CsrfAwareActionInterface on all 5 action controllers (Cache, CacheCss, ConfigUpdate, Cookie, Log/Reset)
  • Add HttpPostActionInterface to restrict state-changing actions to POST method only
  • Add cookie name allowlist in Cookie controller — only qdb_db_profiler, qdb_db_profiler_backtrace, and qdb_appearance are permitted (C1)
  • Remove devadmin config key from ConfigUpdate controller — this allowed disabling admin password lifetime/enforcement from the toolbar (C3)
  • Fix exception catches to use \Throwable instead of unqualified Exception (H9)
  • Update toolbar JS (toolbar.phtml) to send POST requests with FORM_KEY for CSRF protection

Security Findings Addressed

ID Finding Severity
C1 Cookie controller accepts arbitrary cookie names Critical
C3 ConfigUpdate has devadmin case that disables password security Critical
H9 Unqualified Exception catches miss Error subclasses Hygiene

Test plan

  • Verify toolbar button actions (cache flush, CSS cache flush, config toggle) still work via POST
  • Verify GET requests to action controllers return 404
  • Verify requests without valid form_key are rejected
  • Verify Cookie controller rejects non-allowlisted cookie names
  • Verify devadmin config option is no longer available

🤖 Generated with Claude Code

rhoerr and others added 5 commits April 5, 2026 18:14
- Implement CsrfAwareActionInterface on all 5 action controllers
- Add HttpPostActionInterface to restrict to POST method
- Allowlist cookie names in Cookie controller (C1)
- Remove devadmin config key from ConfigUpdate (C3)
- Fix exception catches to use \Throwable (H9)
- Update toolbar JS to send POST with FORM_KEY

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix unreachable else branch by adding explicit $file existence check
- Fix typo: "reseted" → "reset"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The comment explains WHY the Cache-Control header is set (to control
varnish, fastly, and built-in php page caches), which is not obvious
from the code alone.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both validateForCsrf() and createCsrfValidationException() returned null,
which is identical to the default behavior for any action that does NOT
implement CsrfAwareActionInterface. HttpPostActionInterface alone is
sufficient — it restricts routes to POST, and the framework's CsrfValidator
applies standard form_key validation to all POST actions by default.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Curly/smart quotes (U+2018, U+2019) were introduced in the catch
handler string. Replace with straight ASCII quotes for consistency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rhoerr rhoerr marked this pull request as ready for review April 6, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant