Skip to content

Use constant-time comparison for the backend secret key validation#41044

Open
Nexory wants to merge 1 commit into
magento:2.4-developfrom
Nexory:hardening/backend-secretkey-constant-time
Open

Use constant-time comparison for the backend secret key validation#41044
Nexory wants to merge 1 commit into
magento:2.4-developfrom
Nexory:hardening/backend-secretkey-constant-time

Conversation

@Nexory

@Nexory Nexory commented Jul 23, 2026

Copy link
Copy Markdown

Description (*)

BackendValidator::validateRequest() validates the admin secret_key (the anti-CSRF key embedded in backend URLs) with a plain === string comparison:

$validSecretKey = ($secretKeyValue === $secretKey);

This changes it to hash_equals() so the admin secret key is compared in constant time, consistent with how other secret and hash values are compared across the codebase, for example:

  • Magento\Sales\Helper\Guest compares the order protect code with hash_equals((string)$order->getProtectCode(), $protectCode).
  • Magento\Paypal\Controller\Payflow\ReturnUrl compares the request hash with hash_equals(...).
  • The backend's own AbstractAction::_validateSecretKey() and the POST/form-key path (FormKeyValidator) compare the same class of value via Security::compareStrings(), which is itself a hash_equals() wrapper.

hash_equals() is used directly (rather than the Security::compareStrings() wrapper) to keep this file free of a new static-method call, matching the raw hash_equals() usage already present in core.

It is a behavior-preserving change: the equality result is identical for matching, non-matching, and empty-secret cases. No new test is added because there is no behavioral change; existing backend request-validation coverage continues to pass.

Related Pull Requests

#40923 applies constant-time comparison to a different secret (the storefront custom-option download key, a different file); no overlap.

Fixed Issues (if relevant)

None.

Manual testing scenarios (*)

  1. As a logged-in admin, open a backend action whose controller does not implement CsrfAwareActionInterface and does not extend AbstractAction (so the fallback secret-key path runs) with the correct key=<secret_key> URL parameter. The request is accepted, as before.
  2. Repeat with an incorrect key value. The request is rejected with "Invalid security or form key. Please refresh the page.", as before.

There is no functional change; both scenarios behave exactly as they did prior to this PR, only the comparison is now constant-time.

Contribution checklist (*)

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable) - behavior-preserving change, no new test added; existing coverage continues to pass
  • README.md files for modified modules are updated and included in the pull request if any README.md predefined sections require an update - not applicable
  • All automated tests passed successfully (all builds are green) - to be confirmed by CI on this PR

@m2-assistant

m2-assistant Bot commented Jul 23, 2026

Copy link
Copy Markdown

Hi @Nexory. Thank you for your contribution!
Here are some useful tips on how you can test your changes using Magento test environment.
❗ Automated tests can be triggered manually with an appropriate comment:

  • @magento run all tests - run or re-run all required tests against the PR changes
  • @magento run <test-build(s)> - run or re-run specific test build(s)
    For example: @magento run Unit Tests

<test-build(s)> is a comma-separated list of build names.

Allowed build names are:
  1. Database Compare
  2. Functional Tests CE
  3. Functional Tests EE
  4. Functional Tests B2B
  5. Integration Tests
  6. Magento Health Index
  7. Sample Data Tests CE
  8. Sample Data Tests EE
  9. Sample Data Tests B2B
  10. Static Tests
  11. Unit Tests
  12. WebAPI Tests
  13. Semantic Version Checker

You can find more information about the builds here
ℹ️ Run only required test builds during development. Run all test builds before sending your pull request for review.


For more details, review the Code Contributions documentation.
Join Magento Community Engineering Slack and ask your questions in #github channel.

@Nexory

Nexory commented Jul 23, 2026

Copy link
Copy Markdown
Author

@magento run all tests

@Nexory

Nexory commented Jul 23, 2026

Copy link
Copy Markdown
Author

@magento run Magento Health Index

Route the admin secret_key check in BackendValidator through hash_equals() instead of a plain === comparison, consistent with existing constant-time secret/hash comparisons in core (e.g. Sales\Helper\Guest and Paypal ReturnUrl).
@Nexory
Nexory force-pushed the hardening/backend-secretkey-constant-time branch from f50f196 to 279ad1b Compare July 23, 2026 23:42
@Nexory

Nexory commented Jul 23, 2026

Copy link
Copy Markdown
Author

@magento run Static Tests,Unit Tests,Integration Tests,Semantic Version Checker,Magento Health Index

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