Route is sometimes NULL in CsrfExceptionSubscriber

Created on 7 March 2025, 5 months ago

Problem/Motivation

In one of our websites we see the following frequent error message:

Error: Call to a member function hasRequirement() on null in Drupal\Core\EventSubscriber\CsrfExceptionSubscriber->on403() (regel 36 van /path/to/project/web/core/lib/Drupal/Core/EventSubscriber/CsrfExceptionSubscriber.php) #0 /path/to/project/web/core/lib/Drupal/Core/EventSubscriber/HttpExceptionSubscriberBase.php(109): Drupal\Core\EventSubscriber\CsrfExceptionSubscriber->on403()
#1 [internal function]: Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase->onException()
#2 /path/to/project/web/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func()
#3 /path/to/project/vendor/symfony/http-kernel/HttpKernel.php(239): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
#4 /path/to/project/vendor/symfony/http-kernel/HttpKernel.php(91): Symfony\Component\HttpKernel\HttpKernel->handleThrowable()
#5 /path/to/project/web/core/lib/Drupal/Core/StackMiddleware/Session.php(53): Symfony\Component\HttpKernel\HttpKernel->handle()
#6 /path/to/project/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
#7 /path/to/project/web/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
#8 /path/to/project/web/core/modules/ban/src/BanMiddleware.php(50): Drupal\Core\StackMiddleware\ContentLength->handle()
#9 /path/to/project/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\ban\BanMiddleware->handle()
#10 /path/to/project/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
#11 /path/to/project/web/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(36): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
#12 /path/to/project/web/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\Core\StackMiddleware\AjaxPageState->handle()
#13 /path/to/project/web/core/lib/Drupal/Core/DrupalKernel.php(741): Drupal\Core\StackMiddleware\StackedHttpKernel->handle()
#14 /path/to/project/web/index.php(28): Drupal\Core\DrupalKernel->handle()
#15 {main}.

The problem seems to originate in the ban module. I have not yet been able to reproduce the problem / cause.

However, I think the fix should lie in the CsrfExceptionSubscriber itself. The following code expects $route to be an object, but $routeMatch->getRouteObject() may return NULL.

public function on403(ExceptionEvent $event): void {
    $request = $event->getRequest();
    $routeMatch = RouteMatch::createFromRequest($request);
    $route = $routeMatch->getRouteObject();
    if (!$route->hasRequirement('_csrf_token') || empty($route->getOption('_csrf_confirm_form_route'))) {
      return;
    }
    $event->setResponse(new RedirectResponse(Url::fromRoute($route->getOption('_csrf_confirm_form_route'))->toString()));
  }

Steps to reproduce

I have not been able to reproduce the error yet.

Proposed resolution

I think the solution could be as simple as:

  $route = $routeMatch->getRouteObject();
  if (is_null($route) || !$route->hasRequirement('_csrf_token') || empty($route->getOption('_csrf_confirm_form_route'))) {
      return;
    }

Remaining tasks

Fix the issue in Version 10.3 and up. The issue exists is 11 as well.

User interface changes

-

Introduced terminology

-

API changes

-

Data model changes

-

Release notes snippet

-

πŸ› Bug report
Status

Active

Version

10.3 ✨

Component

ban.module

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @Paul Dudink
  • πŸ‡»πŸ‡³Vietnam tuan.hmt

    patch to fix for drupal 10.3.x

  • Status changed to RTBC 10 days ago
  • πŸ‡ΊπŸ‡¦Ukraine AstonVictor

    works for me

    thanks in advance

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Fixed need to be in MRs.

    Also this will need steps to reproduce and probably test coverage

  • πŸ‡ΊπŸ‡¦Ukraine AstonVictor

    refs to steps

    I had an error when trying to replace 404 response with 403 response for some cases.
    e.g. when a user tries to access /user/2 page, but user 2 was removed.

    to replace the response, I used an event subscriber with $events[KernelEvents::EXCEPTION] event
    with a callback smth like :

    if ($event->getThrowable() instanceof NotFoundHttpException && 'user/2' == $path) {
      $event->setThrowable(new AccessDeniedHttpException());
    }
    
  • πŸ‡©πŸ‡ͺGermany rgpublic DΓΌsseldorf πŸ‡©πŸ‡ͺ πŸ‡ͺπŸ‡Ί

    This can happen when you throw an Access Denied exception from a URL that doesn't have a route. That can happen if you write a module that triggers this during an event subscriber. The premises in the original code, that such an exception must only occur when the current page is routed is too strict.

Production build 0.71.5 2024