Dolibarr/dolibarr · error

Access refused by CSRF protection in main.inc.php. Referrer…

Error message

Access refused by CSRF protection in main.inc.php. Referrer of form (${HTTP_REFERER}) is outside the server that serve this page (with method = ${REQUEST_METHOD}).

What it means

filefunc.inc.php performs an early CSRF referrer check for state-changing requests (POST/PUT/etc.): HTTP_REFERER host must match the server's HTTP_HOST (or be empty/allowed). When a form is submitted from a page on another origin, $csrfattack is set, Dolibarr logs a warning, prints this message plus the proxy hint, and dies. It protects against cross-site form posts before the token check (MAIN_SECURITY_CSRF_WITH_TOKEN) later runs.

Solutions

  1. Ensure all HTTP headers are propagated through the proxy: set proxy_set_header Host $host; X-Forwarded-Host, X-Forwarded-Proto and appropriate Referrer-Policy, and make dolibarr_main_url_root match the externally visible URL.
  2. Access Dolibarr using the exact same host name that appears in dolibarr_main_url_root / HTTP_HOST.
  3. For special trusted setups only, add $dolibarr_nocsrfcheck=1 to conf.php to skip this check (reduces security — the token check remains only if MAIN_SECURITY_CSRF_WITH_TOKEN is enabled).
  4. Update Dolibarr: newer versions handle proxies better and allow configuring accepted referrers.
  5. If a third-party site posts to your Dolibarr, embed the form in Dolibarr or use the REST API with tokens instead of cross-origin form posts.

Example fix

// before (nginx)
location / { proxy_pass http://backend; }
// after
location / {
    proxy_pass http://backend;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Referer $http_referer;
}
Defensive patterns

Strategy: fallback

Validate before calling

// before submitting a form programmatically, ensure Referer matches the target host
if (!str_starts_with($referer, 'https://doli.example.com/')) {
    $referer = 'https://doli.example.com/htdocs/'; // set explicitly in the HTTP client
}

Type guard

function refererMatchesHost(?string $referer, string $host): bool {
    if ($referer === null || $referer === '') return true; // empty referer is allowed
    return parse_url($referer, PHP_URL_HOST) === $host;
}

Try / catch

// CSRF refusal ends with die => client sees truncated 200 body, detect by content
$resp = $client->post($url, ['headers' => ['Referer' => $baseUrl.'/'], 'form_params' => $data]);
if (str_contains($resp->getBody(), 'refused by CSRF protection')) {
    // fix Referer/Host headers or configure the proxy, then retry
}

Prevention

When it happens

Trigger: POST request whose HTTP_REFERER points to a different host/port/scheme than the served URL — e.g. form submitted from another domain, or behind a proxy/CDN that rewrites Host or strips/alters Referer headers.

Common situations: Running Dolibarr behind a reverse proxy with URL rewriting where X-Forwarded-Host/Referer are not propagated; accessing the server by two different names (localhost vs domain) and the browser sends the other one; embedded forms/iframe integrations from another origin; browser extensions stripping referers.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of Dolibarr/dolibarr@598aa4bdad (2026-09-14). Data as JSON: /api/errors/3d9871afebb923f9. Report an issue: GitHub.

Appendix: source

Thrown at htdocs/filefunc.inc.php:352

// Note about $_SERVER[HTTP_HOST/SERVER_NAME]: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
// See also CSRF protections done into main.inc.php
if (!defined('NOCSRFCHECK') && isset($dolibarr_nocsrfcheck) && $dolibarr_nocsrfcheck == 1) {    // If $dolibarr_nocsrfcheck is 0, there is a strict CSRF test with token in main
	if (!empty($_SERVER['REQUEST_METHOD']) && !in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD')) && !empty($_SERVER['HTTP_HOST'])) {
		$csrfattack = false;
		if (empty($_SERVER['HTTP_REFERER'])) {
			$csrfattack = true; // An evil browser was used
		} else {
			$tmpa = parse_url($_SERVER['HTTP_HOST']);
			$tmpb = parse_url($_SERVER['HTTP_REFERER']);
			if ((empty($tmpa['host']) ? $tmpa['path'] : $tmpa['host']) != (empty($tmpb['host']) ? $tmpb['path'] : $tmpb['host'])) {
				$csrfattack = true;
			}
		}
		if ($csrfattack) {
			//print 'NOCSRFCHECK='.defined('NOCSRFCHECK').' REQUEST_METHOD='.$_SERVER['REQUEST_METHOD'].' HTTP_HOST='.$_SERVER['HTTP_HOST'].' HTTP_REFERER='.$_SERVER['HTTP_REFERER'];
			// Note: We can't use dol_escape_htmltag here to escape output because lib functions.lib.ph is not yet loaded.
			dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"]." refused by CSRF protection (Bad referrer).", LOG_WARNING);
			print "Access refused by CSRF protection in main.inc.php. Referrer of form (".htmlentities(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'], ENT_COMPAT, 'UTF-8').") is outside the server that serve this page (with method = ".htmlentities($_SERVER['REQUEST_METHOD'], ENT_COMPAT, 'UTF-8').").\n";
			print "If you access your server behind a proxy using url rewriting, you might check that all HTTP headers are propagated (or add the line \$dolibarr_nocsrfcheck=1 into your conf.php file to remove this security check).\n";
			die;
		}
	}
	// Another test is done later on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on.
}
if (empty($dolibarr_main_db_host) && !defined('NOREQUIREDB')) {
	print '<div class="center">Dolibarr setup is not yet complete.<br><br>'."\n";
	print '<a href="install/index.php">Click here to finish Dolibarr install process</a> ...</div>'."\n";
	die;
}
if (empty($dolibarr_main_url_root) && !defined('NOREQUIREVIRTUALURL')) {
	print 'Value for parameter \'dolibarr_main_url_root\' is not defined in your \'htdocs\conf\conf.php\' file.<br>'."\n";
	print 'You must add this parameter with your full Dolibarr root Url (Example: http://myvirtualdomain/ or http://mydomain/mydolibarrurl/)'."\n";
	die;
}

if (empty($dolibarr_main_url_root_alt)) {

View on GitHub (pinned to 598aa4bdad)