Problem/Motivation

RouteHelper::getRouteNameFromRequest() blindly passes $request->getPathInfo() to Url::fromUserInput(), which prepends internal: and dispatches to Url::fromInternalUri(). Core's Url::fromInternalUri() throws an InvalidArgumentException when the resulting path component looks like an external URI. For example, a path of /tel:1234567890 strips to tel:1234567890, which UrlHelper::isExternal() reports as TRUE.

Because ResponseSubscriber::onResponseEvent() is subscribed to KernelEvents::RESPONSE at priority -1000 and calls getRouteNameFromRequest() unconditionally on every response, every request to a path of this shape, even when no routes are configured to be protected, produces an uncaught exception, turning what would have been a clean 404 from Drupal core into a 500 plus a logged PHP error.

This class of bad request seems to be bot- and crawler-generated. Naive HTML link extractors that don't honor the tel: / mailto: URI schemes treat the href value as a relative path and resolve it against the page's host, producing requests like https://example.com/tel:8006564673. Drupal core handles these fine on its own (404, no exception). It is only the presence of this module's response subscriber that escalates them to 500s.

Steps to reproduce

  1. Install Route Basic Authentication on any Drupal 10 or 11 site.
  2. Do not configure any protected_routes (the bug reproduces regardless, but the empty-config case proves the module needn't be doing any actual work to fail).
  3. curl -i https://example.com/tel:8006564673

Expected: HTTP 404 (Drupal core's normal not-found behavior for unrouted paths).

Actual: HTTP 500, with the following entry in watchdog:

InvalidArgumentException: The internal path component 'tel:8006564673' is external.
You are not allowed to specify an external URL together with internal:/.
in Drupal\Core\Url::fromInternalUri() (line 422 of core/lib/Drupal/Core/Url.php).

Backtrace (top frames):

#0 core/lib/Drupal/Core/Url.php(319): Drupal\Core\Url::fromInternalUri()
#1 core/lib/Drupal/Core/Url.php(221): Drupal\Core\Url::fromUri()
#2 modules/contrib/route_basic_auth/src/Routing/RouteHelper.php(27): Drupal\Core\Url::fromUserInput()
#3 modules/contrib/route_basic_auth/src/EventSubscriber/ResponseSubscriber.php(104): Drupal\route_basic_auth\Routing\RouteHelper->getRouteNameFromRequest()

The same fault reproduces for any request path whose first segment parses as an external URI, e.g.:

  • /mailto:foo@example.com
  • /https://example.com
  • /http://example.com

Proposed resolution

Guard RouteHelper::getRouteNameFromRequest() against paths that UrlHelper::isExternal() would classify as external before calling Url::fromUserInput(), and wrap the call in a defensive try/catch for \InvalidArgumentException to cover anything that slips past the scheme check. Return NULL in either case. If the requests cannot match a Drupal route by definition, the module does nothing.

Remaining tasks

  • Review patch.
  • Add test coverage for the external-path case in getRouteNameFromRequest().

User interface changes

None

API changes

None

Data model changes

None

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

fmitchell created an issue. See original summary.

fmitchell’s picture

Title: Fatal `InvalidArgumentException` from `Url::fromUserInput()` when request path looks external (e.g. `/tel:...`, `/mailto:...`, `/https://...`) » Fatal InvalidArgumentException from Url::fromUserInput() when request path looks external (e.g. /tel:..., /mailto:..., /https://...)

fmitchell’s picture

Version: 8.x-1.x-dev » 2.x-dev
fmitchell’s picture

Status: Active » Needs review

Added merge request

darvanen’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Looks great, let's kick off our test suite with a kernel test to lock this in. The CI is in place to support it.

fmitchell’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests

I added a few kernel tests and they pass. Confirm that removing the fix makes the tests fail: https://git.drupalcode.org/issue/route_basic_auth-3603890/-/jobs/10499047

darvanen’s picture

Assigned: fmitchell » Unassigned
Status: Needs review » Reviewed & tested by the community

Thanks for that, added a line without which Drupal 12 will trip us up. It's merging now.

  • darvanen committed 7fd1349b on 2.x authored by fmitchell
    fix: #3603890 Fatal InvalidArgumentException from Url::fromUserInput()...
darvanen’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.