Dolibarr/dolibarr · warning
Access refused to by SQL or Script injection protection in…
Error message
Access refused to ${ip} by SQL or Script injection protection in main.inc.php:analyseVarsForSqlAndScriptsInjection type=${type} Try to go back, fix data of your form and resubmit it. You can contact also your technical support. What it means
Dolibarr's built-in WAF (waf.inc.php, analyseVarsForSqlAndScriptsInjection) scanned GET/POST/COOKIE parameters and found content matching SQL-injection or script-injection testSqlAndScriptInject patterns. It responds HTTP 403 with this message instead of executing the request. The detailed parameter name/value is appended to errormessage2 (and to the audit/security log) but deliberately hidden from the client to avoid text injection.
Solutions
- Identify the offending parameter from the server error log/audit table (paramkey/paramvalue in errormessage2) and remove/escape the suspicious content in the form data.
- If the field legitimately needs HTML, set the module's permission so Dolibarr sanitizes it properly, or allow the page/variable by defining the appropriate exception constant (e.g. MAIN_SECURITY_ALLOWED_PATTERN / use dol_htmlcleanlastbr and GETPOST with proper type) in code rather than weakening the WAF.
- Update Dolibarr: older versions had over-broad regexes that false-positived on innocuous input like 'select' in normal text.
- Check for a real attack: if you did not submit this data, investigate the client/IP — the block is working as intended.
- As a last resort for trusted internal pages only, guard the entry file with define('NOSCANPOSTFORINJECTION', 1) before including main.inc.php — never globally.
Example fix
// before (page killed by WAF)
$_POST['note'] = $_POST['note']; // raw HTML/SQL-ish content passed through
// after (sanitize before it reaches WAF-sensitive storage)
$note = GETPOST('note', 'restricthtml');
$object->note_public = dol_htmlcleanlastbr($note); Defensive patterns
Strategy: validation
Validate before calling
// client-side: strip content the WAF considers injection before sending
function safeForDolibarr(string $value): string {
if (preg_match('/(<\s*script|union\s+select|--\s|\/\*|on\w+\s*=)/i', $value)) {
throw new InvalidArgumentException('Payload would trip Dolibarr WAF; encode or sanitize first');
}
return $value;
} Type guard
function looksLikeInjection(string $v): bool {
return (bool) preg_match('/(<\s*script|javascript:|union\s+select|base64_decode|on(?:load|error)\s*=)/i', $v);
} Try / catch
try {
$resp = $client->post($url, ['form_params' => $data]);
} catch (ClientException $e) {
if ($e->getResponse()->getStatusCode() === 403
&& str_contains((string) $e->getResponse()->getBody(), 'injection protection')) {
// sanitize/encode the offending field and retry once
}
} Prevention
- Sanitize rich-text fields with Dolibarr's GETPOST(...,'restricthtml')/dol_escape helpers before posting.
- Scan payloads (paste buffers, imported files) for script/SQL fragments before submission.
- Treat unexpected 403s with this message as either your own payload or an active attacker — check audit logs.
- Keep Dolibarr updated; WAF false positives get fixed in releases.
- Never disable the WAF globally to work around a single field.
When it happens
Trigger: Any request whose variable content contains patterns like UNION SELECT, <script>, onload=, base64-encoded script tags, or SQL comments, submitted via GET/POST/COOKIE on any Dolibarr page, when the value fails testSqlAndScriptInject() for the given variable type.
Common situations: A legitimate form field accepting rich text/HTML (notes, descriptions) tripping the filter; security scanners or penetration tests; users pasting code snippets into text fields; integrating an API client that sends raw SQL-looking strings or HTML payloads.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- Security injection exception
- Access refused with request method TRACE
- Bad link. File is from another module part.
- Access to a page that needs a token (constant…
- Access to this page this way (POST method or GET with a…
AI-assisted analysis of Dolibarr/dolibarr@598aa4bdad (2026-09-14).
Data as JSON: /api/errors/befde4fb559eb0a3.
Report an issue: GitHub.
Appendix: source
Thrown at htdocs/waf.inc.php:275
{
if (is_array($var)) {
foreach ($var as $key => $value) { // Warning, $key may also be used for attacks
// Exclude check for some variable keys
if ($type === 0 && defined('NOSCANPOSTFORINJECTION') && is_array(constant('NOSCANPOSTFORINJECTION')) && in_array($key, (array) constant('NOSCANPOSTFORINJECTION'))) {
continue;
}
// Test on both the key (we force type to 1 for test on key, we must accept key like "delete=1" blocked with type 3) and the value
if (analyseVarsForSqlAndScriptsInjection($key, 1, $stopcode) && analyseVarsForSqlAndScriptsInjection($value, $type, $stopcode)) {
//$var[$key] = $value; // This is useless
} else {
http_response_code(403);
// Get remote IP: PS: We do not use getUserRemoteIP(), function is not yet loaded and we need a value that can't be spoofed
$ip = (empty($_SERVER['REMOTE_ADDR']) ? 'unknown' : $_SERVER['REMOTE_ADDR']);
if ($stopcode) {
$errormessage = 'Access refused to '.htmlentities($ip, ENT_COMPAT, 'UTF-8').' by SQL or Script injection protection in main.inc.php:analyseVarsForSqlAndScriptsInjection type='.htmlentities((string) $type, ENT_COMPAT, 'UTF-8');
//$errormessage .= ' paramkey='.htmlentities($key, ENT_COMPAT, 'UTF-8'); // Disabled to avoid text injection
$errormessage2 = 'page='.htmlentities((empty($_SERVER["REQUEST_URI"]) ? '' : $_SERVER["REQUEST_URI"]), ENT_COMPAT, 'UTF-8');
$errormessage2 .= ' paramtype='.htmlentities((string) $type, ENT_COMPAT, 'UTF-8');
$errormessage2 .= ' paramkey='.htmlentities($key, ENT_COMPAT, 'UTF-8');
$errormessage2 .= ' paramvalue='.htmlentities($value, ENT_COMPAT, 'UTF-8');
print $errormessage;
print "<br>\n";
print 'Try to go back, fix data of your form and resubmit it. You can contact also your technical support.';
print "\n".'<!--'."\n";
print $errormessage2;
print "\n".'-->';
// Add entry into the PHP server error log
if (function_exists('error_log')) {
error_log($errormessage.' '.substr($errormessage2, 2000));View on GitHub (pinned to 598aa4bdad)