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

  1. Fix the caller so original_file is a clean module-relative path (no leading slashes, no '..')
  2. Sanitize the filename server-side before redirecting to document.php (strip '..' and forbidden characters with dol_sanitizeFileName)
  3. If the file legitimately lives outside the module dir, use the ecm/directory hash (hashp) mechanism instead of a relative traversal path
  4. 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

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


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)