{"record":{"id":"befde4fb559eb0a3","repo":"Dolibarr/dolibarr","slug":"access-refused-to-ip-by-sql-or-script-injection-protection","errorCode":null,"errorMessage":"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.","messagePattern":"Access refused to (.+?) by SQL or Script injection protection in main\\.inc\\.php:analyseVarsForSqlAndScriptsInjection type=(.+?) Try to go back, fix data of your form and resubmit it\\. You can contact also your technical support\\.","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"htdocs/waf.inc.php","lineNumber":275,"sourceCode":"{\n\tif (is_array($var)) {\n\t\tforeach ($var as $key => $value) {\t// Warning, $key may also be used for attacks\n\t\t\t// Exclude check for some variable keys\n\t\t\tif ($type === 0 && defined('NOSCANPOSTFORINJECTION') && is_array(constant('NOSCANPOSTFORINJECTION')) && in_array($key, (array) constant('NOSCANPOSTFORINJECTION'))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 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\n\t\t\tif (analyseVarsForSqlAndScriptsInjection($key, 1, $stopcode) && analyseVarsForSqlAndScriptsInjection($value, $type, $stopcode)) {\n\t\t\t\t//$var[$key] = $value;\t// This is useless\n\t\t\t} else {\n\t\t\t\thttp_response_code(403);\n\n\t\t\t\t// Get remote IP: PS: We do not use getUserRemoteIP(), function is not yet loaded and we need a value that can't be spoofed\n\t\t\t\t$ip = (empty($_SERVER['REMOTE_ADDR']) ? 'unknown' : $_SERVER['REMOTE_ADDR']);\n\n\t\t\t\tif ($stopcode) {\n\t\t\t\t\t$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');\n\t\t\t\t\t//$errormessage .= ' paramkey='.htmlentities($key, ENT_COMPAT, 'UTF-8');\t// Disabled to avoid text injection\n\n\t\t\t\t\t$errormessage2 = 'page='.htmlentities((empty($_SERVER[\"REQUEST_URI\"]) ? '' : $_SERVER[\"REQUEST_URI\"]), ENT_COMPAT, 'UTF-8');\n\t\t\t\t\t$errormessage2 .= ' paramtype='.htmlentities((string) $type, ENT_COMPAT, 'UTF-8');\n\t\t\t\t\t$errormessage2 .= ' paramkey='.htmlentities($key, ENT_COMPAT, 'UTF-8');\n\t\t\t\t\t$errormessage2 .= ' paramvalue='.htmlentities($value, ENT_COMPAT, 'UTF-8');\n\n\t\t\t\t\tprint $errormessage;\n\t\t\t\t\tprint \"<br>\\n\";\n\t\t\t\t\tprint 'Try to go back, fix data of your form and resubmit it. You can contact also your technical support.';\n\n\t\t\t\t\tprint \"\\n\".'<!--'.\"\\n\";\n\t\t\t\t\tprint $errormessage2;\n\t\t\t\t\tprint \"\\n\".'-->';\n\n\t\t\t\t\t// Add entry into the PHP server error log\n\t\t\t\t\tif (function_exists('error_log')) {\n\t\t\t\t\t\terror_log($errormessage.' '.substr($errormessage2, 2000));","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/Dolibarr/dolibarr/blob/598aa4bdada683d17ca04b1842548821ff0eb6c6/htdocs/waf.inc.php#L257-L293","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (page killed by WAF)\n$_POST['note'] = $_POST['note']; // raw HTML/SQL-ish content passed through\n// after (sanitize before it reaches WAF-sensitive storage)\n$note = GETPOST('note', 'restricthtml');\n$object->note_public = dol_htmlcleanlastbr($note);","handlingStrategy":"validation","validationCode":"// client-side: strip content the WAF considers injection before sending\nfunction safeForDolibarr(string $value): string {\n    if (preg_match('/(<\\s*script|union\\s+select|--\\s|\\/\\*|on\\w+\\s*=)/i', $value)) {\n        throw new InvalidArgumentException('Payload would trip Dolibarr WAF; encode or sanitize first');\n    }\n    return $value;\n}","typeGuard":"function looksLikeInjection(string $v): bool {\n    return (bool) preg_match('/(<\\s*script|javascript:|union\\s+select|base64_decode|on(?:load|error)\\s*=)/i', $v);\n}","tryCatchPattern":"try {\n    $resp = $client->post($url, ['form_params' => $data]);\n} catch (ClientException $e) {\n    if ($e->getResponse()->getStatusCode() === 403\n        && str_contains((string) $e->getResponse()->getBody(), 'injection protection')) {\n        // sanitize/encode the offending field and retry once\n    }\n}","preventionTips":["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."],"tags":["waf","security","sql-injection","xss","http-403"],"backgroundTag":"sql-query-failed","analyzedSha":"598aa4bdada683d17ca04b1842548821ff0eb6c6","analyzedAt":"2026-09-14T11:12:15.309Z","contentChangedAt":"2026-09-14T11:12:15.309Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}