No Code Attached Yet
avatar velisnolis
velisnolis
27 Oct 2026

What happened?

  1. Enable System - SEF with Strict routing = Yes (SEF URLs and URL rewriting on).
  2. Install a component that registers a RouterFactory in its service provider but has no site router class (<Namespace>\Site\Service\Router). Real-world examples: Akeeba Backup 10.0.0 (com_akeebabackup) and Regular Labs ReReplacer (com_rereplacer), which are backend-only.
  3. Request a non-SEF frontend URL for that component with any extra query parameter, e.g.:
    GET https://example.com/?option=com_akeebabackup&view=json&json=x

The request is answered with 301 Location: https://example.com/ and this warning is logged:

PHP Warning:  Uninitialized string offset 0 in .../libraries/vendor/joomla/application/src/AbstractWebApplication.php on line 418

In our case the trigger was an external monitoring tool probing Akeeba's legacy JSON API URL, but any visitor can trigger it with a crafted URL.

Version

6.2

Expected result

When the SEF URL can't be built, enforceSEF() should leave the request alone: no redirect, and the component (or a 404) handles it as it would with strict routing off.

Actual result

A 301 redirect to the site root, plus a PHP warning in the error log on every such request.

Call chain:

  1. Sef::onAfterRoute() → enforceSEF() (plugins/system/sef/src/Extension/Sef.php, line 164).
  2. $newRoute = Route::_($parsedVars, false); (line 542).
  3. SiteRouter::buildComponentPreprocess() → getComponentRouter() → bootComponent()->createRouter() → RouterFactory::createRouter() throws RuntimeException('No router available for this application.') because the site router class doesn't exist (libraries/src/Component/Router/RouterFactory.php, line 86).
  4. Route::_() catches the RuntimeException and returns null (libraries/src/Router/Route.php, lines 100-105, the B/C behaviour deprecated since 3.9).
  5. Back in enforceSEF(): new Uri(null) has no query and $route !== null, so it calls $app->redirect(null, 301) (line 546).
  6. In AbstractWebApplication::redirect(), preg_split() turns null into '', $url[0] raises the warning (line 418), and the empty URL is resolved as relative to the current path, i.e. the site root.

The "tainted" branch in onAfterRoute() (lines 139-144) has the same unchecked Route::_() result.

The code is unchanged in 6.2-dev, 6.1-dev and 5.4-dev.

System Information

  • Joomla 6.2.0
  • PHP 8.4.27 (CloudLinux, cPanel)
  • System - SEF: enabled, strict routing on; System - Language Filter: disabled

Additional Comments

Suggested fix: bail out when the route can't be built, in both places:

$newRoute = Route::_($parsedVars, false);

if ($newRoute === null) {
    return;
}

There's no security impact: the redirect target is always the site root, and nothing is disclosed. It does cause error-log noise that anyone can trigger, and it breaks frontend non-SEF URLs of such components (e.g. URL-triggered tasks), which get redirected to the homepage instead of reaching the component.

I can test a PR if that helps.

avatar velisnolis velisnolis - open - 27 Oct 2026
avatar joomla-cms-bot joomla-cms-bot - change - 27 Oct 2026
Labels Added: No Code Attached Yet
avatar joomla-cms-bot joomla-cms-bot - labeled - 27 Oct 2026
avatar velisnolis velisnolis - change - 27 Oct 2026
The description was changed
avatar velisnolis velisnolis - edited - 27 Oct 2026

Add a Comment

Login with GitHub to post a comment