Dolibarr/dolibarr · warning
ErrorLoginMustBePostMethod
Error message
ErrorLoginMustBePostMethod
What it means
Dolibarr refuses login submissions where the password arrives in the query string via GET, to keep passwords out of browser history, Referrer headers and proxy logs (CWE-598). The only GET exception is OAuth callbacks flagged by afteroauthloginreturn. The login form must submit via POST.
Solutions
- Change the login form to method="post".
- Rewrite any custom script to send credentials in the POST body, not the URL.
- For legitimate OAuth callback flows, ensure the afteroauthloginreturn parameter is set instead of sending passwords via GET.
- Rotate any credentials that already leaked into access logs/browser history; update offending third-party plugins.
Example fix
// before
header('Location: index.php?actionlogin=login&username=u&password=p');
// after
// use a POST form:
echo '<form method="post" action="index.php"><input type="hidden" name="actionlogin" value="login">...</form>'; Defensive patterns
Strategy: validation
Validate before calling
if (isset($_GET['password']) || (isset($_GET['username']) && isset($_GET['actionlogin']))) { die('Credentials must be submitted via POST'); } Prevention
- Always use POST forms for authentication UIs
- Scan access logs for credentials in query strings and rotate them
- Test integrations with a proxy to confirm no secrets in URLs
When it happens
Trigger: A form or script builds a URL like index.php?actionlogin=login&username=x&password=y and requests it with GET; GETPOST('password') present while actionlogin=login and no afteroauthloginreturn parameter.
Common situations: Custom login/SSO scripts hand-crafting GET login URLs; links saved in browser history from a misconfigured form with method=GET; third-party plugins performing GET-based logins that should migrate to POST or the OAuth path.
Related errors
- Access to a page that needs a token (constant…
- Access to this page this way (POST method or GET with a…
- If you access your server behind a proxy using url…
- Access refused with request method TRACE
- ErrorFileNameInvalid
AI-assisted analysis of Dolibarr/dolibarr@598aa4bdad (2026-09-14).
Data as JSON: /api/errors/eca3d125d8138e58.
Report an issue: GitHub.
Appendix: source
Thrown at htdocs/main.inc.php:763
$langs->setDefaultLang($langcode);
}
// Test HTTP header
if (!empty($_SERVER['HTTP_EXPOSED_CREDENTIAL_CHECK'])) {
// TODO Read option $dolibarr_main_no_leaked_credentials with value 1, 2, ... and return
//dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"].' refused by option $dolibarr_main_no_leaked_credentials='.$dolibarr_main_no_leaked_credentials, LOG_NOTICE);
dol_syslog('--- Security warning: credentials reported as leaked were used to try to login. HTTP_EXPOSED_CREDENTIAL_CHECK='.((int) $_SERVER['HTTP_EXPOSED_CREDENTIAL_CHECK']), LOG_NOTICE);
}
// Refuse a login submission that carries a password in a GET query string.
// This avoids the password ending up in web server access logs,
// the browser history, the Referrer header or any HTTP proxy log (CWE-598).
// OAuth callbacks legitimately use GET but use afteroauthloginreturn.
// Other external pluginn using login_hashin GET are also legitimate.
if (GETPOST('actionlogin', 'aZ09') == 'login' && !GETPOST('afteroauthloginreturn', 'alphanohtml', 1) && GETPOST('password', 'password', 1)) {
dol_syslog("--- Login submission with credentials in the query string refused for ".$_SERVER["PHP_SELF"], LOG_WARNING);
$langs->loadLangs(array('main', 'errors'));
$_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorLoginMustBePostMethod");
$test = false;
}
// Validation of login/pass/entity
// If ok, the variable login will be returned
// If error, we will put error message in session under the name dol_loginmesg
if ($test && $goontestloop && GETPOST('actionlogin', 'aZ09') != 'disabled' && (GETPOST('actionlogin', 'aZ09') == 'login' || $dolibarr_main_authentication != 'dolibarr')) {
// Loop on each test mode defined into $authmode
// $authmode is an array for example: array('0'=>'dolibarr', '1'=>'googleoauth');
$oauthmodetotestarray = array('google');
foreach ($oauthmodetotestarray as $oauthmodetotest) {
if (in_array($oauthmodetotest.'oauth', $authmode)) { // This is an authmode that is currently qualified. Do we have to remove it ?
// If we click on the link to use OAuth authentication or if we go here after a callback return, we do nothing
if (GETPOST('beforeoauthloginredirect') == $oauthmodetotest || GETPOST('afteroauthloginreturn') == $oauthmodetotest) {
continue;
}
dol_syslog("User did not click on link for OAuth mode ".$oauthmodetotest.", param beforeoauthloginredirect is ".GETPOST('beforeoauthloginredirect')." and param afteroauthloginreturn is ".GETPOST('afteroauthloginreturn')." so we disable check of login for mode ".$oauthmodetotest);
foreach ($authmode as $tmpkey => $tmpval) {View on GitHub (pinned to 598aa4bdad)