Dolibarr/dolibarr · warning
ErrorFileNameInvalid
Error message
ErrorFileNameInvalid: ${original_file} What it means
document.php refuses to deliver a file whose path contains directory-traversal sequences ('..') or pipe/redirection characters ('<', '>','|'). It prints 'ErrorFileNameInvalid' followed by the HTML-escaped requested filename and exits. This is a security guard against path traversal and command-injection-style filenames when serving documents from htdocs/document.php:332-336.
Solutions
- Fix the caller so original_file is a clean module-relative path (no leading slashes, no '..')
- Sanitize the filename server-side before redirecting to document.php (strip '..' and forbidden characters with dol_sanitizeFileName)
- If the file legitimately lives outside the module dir, use the ecm/directory hash (hashp) mechanism instead of a relative traversal path
- Check for double-encoding: decode the URL once and re-verify the path does not contain '..' after decoding
Example fix
// before
$url = DOL_URL_ROOT.'/document.php?modulepart=facture&original_file=../../'.$relative;
// after
$clean = str_replace('..', '', dol_sanitizeFileName($relative));
$url = DOL_URL_ROOT.'/document.php?modulepart=facture&original_file='.urlencode($clean); Defensive patterns
Strategy: validation
Validate before calling
if (preg_match('/\.\./', $path) || preg_match('/[<>|]/', $path)) { throw new InvalidArgumentException('Invalid file path'); } Type guard
function isSafeRelativePath(string $p): bool { return $p !== '' && strpos($p, '..') === false && !preg_match('/[<>|]/', $p) && strpos($p, "\0") === false; } Prevention
- Always build original_file from module-relative paths, never concatenate user input
- Run filenames through dol_sanitizeFileName before storing or linking
- URL-encode the file parameter exactly once and avoid double decoding
- Prefer hashp-based links for files outside the standard module tree
When it happens
Trigger: GET/POST to document.php with original_file (or the resolved $fullpath_original_file) containing '..' segments or the characters <, >, or |; e.g. original_file=../../conf/conf.php or a filename containing a pipe character.
Common situations: Malformed or hand-crafted download links; applications building original_file by concatenating user input; storage backends (e.g. some external storages) that re-derive relative paths with ../; legacy clients URL-encoding filenames that contain pipes.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
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…
- ErrorLoginMustBePostMethod
- ErrorFileDoesNotExists
AI-assisted analysis of Dolibarr/dolibarr@598aa4bdad (2026-09-14).
Data as JSON: /api/errors/34d89fb48c85e18f.
Report an issue: GitHub.
Appendix: source
Thrown at htdocs/document.php:339
if ($num > 0) {
$accessallowed = 1;
}
}
}
}
}
// Security:
// Limit access if permissions are wrong
if (!$accessallowed) {
accessforbidden();
}
// Security:
// We refuse directory transversal change and pipes in file names
if (preg_match('/\.\./', $fullpath_original_file) || preg_match('/[<>|]/', $fullpath_original_file)) {
dol_syslog("Refused to deliver file ".$fullpath_original_file);
print "ErrorFileNameInvalid: ".dol_escape_htmltag($original_file);
exit;
}
clearstatcache();
$filename = basename($fullpath_original_file);
$filename = preg_replace('/\.noexe$/i', '', $filename);
// Output file on browser
dol_syslog("document.php download $fullpath_original_file filename=$filename content-type=$type");
$fullpath_original_file_osencoded = dol_osencode($fullpath_original_file); // New file name encoded in OS encoding charset
// This test if file exists should be useless. We keep it to find bug more easily
if (!file_exists($fullpath_original_file_osencoded)) {
dol_syslog("ErrorFileDoesNotExists: ".$fullpath_original_file);
print $langs->trans("ErrorFileDoesNotExists") . ' : ' . dol_escape_htmltag($original_file);
exit;View on GitHub (pinned to 598aa4bdad)