Skip to content
← All PrestaShop 9 errors

PrestaShop 9 errors

403 Forbidden on a module's ajax.php in PrestaShop 9

PrestaShop 9 blocks direct access to PHP files inside the modules folder. Modules that answer AJAX through their own ajax.php get 403 Forbidden, and the feature behind it stops working.

The error
403 Forbidden: /modules/mymodule/ajax.php
Removed in
PrestaShop 9.0
Usually found in
Older modules with their own PHP endpoints

What happened

PrestaShop 9 adds a modules/.htaccess file that denies direct web access to .php, .tpl, .twig, .json, .yml, .log, .txt and config.xml files inside the modules folder. It closes an old security hole: many attacks on PrestaShop stores went through forgotten PHP scripts in module folders.

The side effect: modules that answer requests through their own file, such as modules/mymodule/ajax.php, cron.php or upload.php, now get 403 Forbidden. There is no PHP error and nothing in the PrestaShop log. A button or filter simply does nothing, and the browser's developer tools show the 403 response.

This applies to Apache. On Nginx the rule has to be added to the server configuration, so the same modules may still work there, along with the security hole.

The fix

Move the endpoint into a module front controller. That is the standard way since PrestaShop 1.5, so it works in every version:

// modules/mymodule/controllers/front/ajax.php
class MyModuleAjaxModuleFrontController extends ModuleFrontController
{
    public function postProcess()
    {
        $result = ['ok' => true];
        $this->ajaxRender(json_encode($result));
        exit;
    }
}

Build its address with the link class instead of hard-coding the path:

$url = $this->context->link->getModuleLink('mymodule', 'ajax', [], true);

Cron scripts become a front controller too, protected with a secret token in the URL.

Do not delete or loosen modules/.htaccess to bring the old file back. The next upgrade restores it, and it is there for a reason.

Where else it hides

find modules -maxdepth 2 -name "*.php" ! -name "index.php" | grep -v "/vendor/"

Then check which of those files the module calls from JavaScript or a cron job: the main module file (mymodule.php) is fine, it is never opened directly.

Find every place like this before you upgrade

Where one removed call is, there are usually more. Our free PrestaShop 9 Readiness Check reads the code of every module, the theme and the overrides and lists each problem with its file and line. It only reads, nothing is changed.

Get the free check

Prefer not to fix it yourself? We upgrade stores to PrestaShop 9 for a fixed price. See the upgrade