java-topology/whitepaper/outreach/dolibarr.md
russell@unturf.com 6784cdf1cf feat: add 39 outreach docs (batches 6-8)
Batch 6 (9): dolibarr, jitsi-videobridge, zed, tryton, suricata,
  strawberry, zulip, zesarux, zephyr
Batch 7 (15): xonotic (4), xash3d (3), xenia, xtuple, zabbix (2),
  zathura, zebra, yabause, zephyr-0001
Batch 8 (15): woodpecker (2), wine (4), widelands (3), wesnoth (3),
  wekan (3)

Mix of CWE-407 and CWE-312.
2026-04-14 17:06:28 -04:00

6.3 KiB

Dolibarr ERP/CRM — CWE-407 + CWE-312 Disclosure Brief

2026-04-13 · Patches available — awaiting upstream merge

Finding

Five defects in Dolibarr ERP/CRM across the file integrity checker, GDPR data policy cron, bookkeeping reversal system, email collector, and LDAP login module. Three CWE-407 algorithmic complexity defects and two CWE-312 cleartext credential logging defects. All patched. Patches ready for upstream review.

The Defects

dolibarr-0001 (PATCHED — HIGH): htdocs/blockedlog/admin/filecheck.php:409

// in_array() — O(N) linear scan over $file_list['insignature']
if (!in_array($tmprelativefilename, $file_list['insignature'])) {

$file_list['insignature'] grows with the number of tracked files (I). Each scanned file (S) triggers an O(I) linear scan via in_array(). Total cost: O(S*I). At S=10,000 scanned files and I=8,000 signature entries, this fires ~80,000,000 comparisons during a file integrity check.

dolibarr-0002 (PATCHED — MEDIUM): htdocs/datapolicy/class/datapolicycron.class.php:370

// in_array() — O(N) scan over growing $processedIds list
if (in_array($obj->rowid, $processedIds) || !method_exists($this, $handlerMethod)) {

$processedIds grows as records get processed. Each new record checks in_array() against all previously processed IDs. Total cost: O(N^2) where N = records processed per GDPR policy action.

dolibarr-0003 (PATCHED — MEDIUM): htdocs/accountancy/class/bookkeeping.class.php:3753

// in_array() — O(A) scan over $alreadyExtourneT
if (in_array($bookKeeping->piece_num, $alreadyExtourneT)) {

$alreadyExtourneT holds all previously reversed accounting entries. Each bookkeeping entry (P) triggers an O(A) linear scan. Total cost: O(P*A). Fires during accounting reversal operations at fiscal year boundaries.

dolibarr-0004 (PATCHED — HIGH, CWE-312): htdocs/admin/emailcollector_card.php:575

// IMAP password logged verbatim — unconditional
dol_syslog("imap_open connectstring=".$connectstringsource." login=".$object->login." password=".$object->password."...");

The IMAP email collector logs the mail account password in plaintext to dol_syslog() on every connection attempt. Not gated on any debug flag. Any log aggregator, syslog daemon, or shared hosting log directory exposes the credential.

dolibarr-0005 (PATCHED — MEDIUM, CWE-312): htdocs/core/login/functions_ldap.php:98

// LDAP admin searchPassword first 3 chars logged + printed to browser
dol_syslog("... Pass:".dol_trunc($ldap->searchPassword, 3));
print "DEBUG: ... Pass:".dol_trunc($ldap->searchPassword, 3)."<br>\n";

When $ldapdebug flag activates, the LDAP admin bind password prefix leaks to both server logs and browser output. The dol_trunc() call still exposes the first 3 characters, enough to narrow brute-force attacks.

Complexity Proof

dolibarr-0001: At S=10,000 scanned files, I=8,000 signatures:

  • Defective: 10,000 * 8,000 = 80,000,000 comparisons
  • Fixed: 10,000 * 1 = 10,000 lookups (array_flip + isset)
  • 83.5x speedup measured.

dolibarr-0002: At N=1,000 records:

  • Defective: 1 + 2 + ... + 1,000 = ~500,000 comparisons
  • Fixed: 1,000 lookups (array_flip + isset)
  • 23.8x speedup measured.

dolibarr-0003: At P=500 entries, A=400 reversed:

  • Defective: 500 * 400 = 200,000 comparisons
  • Fixed: 500 lookups (isset on flipped array)
  • 39.9x speedup measured.

Impact

Dolibarr serves over 100,000 businesses worldwide as an open-source ERP/CRM. The file integrity checker (dolibarr-0001) runs during security audits and admin panel checks. The GDPR data policy cron (dolibarr-0002) runs on schedule for EU compliance. The accounting reversal (dolibarr-0003) fires at fiscal year boundaries when accountants process bulk reversals.

The credential logging defects (dolibarr-0004, dolibarr-0005) expose mail and LDAP passwords in production log files. dolibarr-0004 fires unconditionally on every IMAP connection. dolibarr-0005 fires when LDAP debug mode activates, which administrators enable during directory integration troubleshooting.

The Fix

dolibarr-0001: array_flip() the signature list once, then isset() for O(1) lookups:

// Before
if (!in_array($tmprelativefilename, $file_list['insignature'])) {

// After
$insignature_set = array_flip($file_list['insignature']);
if (!isset($insignature_set[$tmprelativefilename])) {

dolibarr-0002: array_flip() the processed IDs, maintain the flipped set alongside the list:

// Before
if (in_array($obj->rowid, $processedIds) || ...) {

// After
$processedSet = array_flip($processedIds);
if (isset($processedSet[$obj->rowid]) || ...) {
// ... on success:
$processedSet[$obj->rowid] = true;

dolibarr-0003: Same pattern, flipped array for O(1) membership:

$alreadyExtourneSet = array();
// ... populate alongside $alreadyExtourneT
if (isset($alreadyExtourneSet[$bookKeeping->piece_num])) {

dolibarr-0004: Replace password with literal ***:

dol_syslog("imap_open connectstring=".$connectstringsource." login=".$object->login." password=*** ...");

dolibarr-0005: Replace dol_trunc() with literal *** in both log and print:

dol_syslog("... Pass:***");
print "DEBUG: ... Pass:***<br>\n";

Patch

Fixes available:

  • defects/dolibarr/patch/dolibarr-0001-filecheck-insignature-in_array.patch
  • defects/dolibarr/patch/dolibarr-0002-datapolicycron-processedIds-in_array.patch
  • defects/dolibarr/patch/dolibarr-0003-bookkeeping-extourne-in_array.patch
  • defects/dolibarr/patch/dolibarr-0004-emailcollector-imap-password-logged.patch
  • defects/dolibarr/patch/dolibarr-0005-ldap-searchpassword-logged.patch

CWE-407 speedups: dolibarr-0001 83.5x, dolibarr-0002 23.8x, dolibarr-0003 39.9x. CWE-312 fixes eliminate credential exposure in logs.

What We Ask

Patches ready for review.

  1. Confirm receipt and assign a GitHub issue reference (Dolibarr/dolibarr).
  2. Assess severity — dolibarr-0004 logs IMAP passwords unconditionally; dolibarr-0001 fires on every file integrity check.
  3. Coordinate a disclosure date — we target 90 days from first contact.
  4. We will credit the Dolibarr team in the public disclosure. Preferred acknowledgment format welcome.

Contact: see cover email. This brief is confidential until coordinated disclosure.