CVE-2021-41276: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection') (CWE-74)
value: Tuleap is a Libre and Open Source tool for end to end traceability of application and system developments. In affected versions Tuleap does not sanitize properly the search filter built from the ldap_id attribute of a user during the daily synchronization. A malicious user could force accounts to be suspended or take over another account by forcing the update of the ldap_uid attribute. Note that the malicious user either need to have site administrator capability on the Tuleap instance or be an LDAP operator with the capability to create/modify account. The Tuleap instance needs to have the LDAP plugin activated and enabled for this issue to be exploitable. This issue has been patched in Tuleap Community Edition 13.2.99.31, Tuleap Enterprise Edition 13.1-5, and Tuleap Enterprise Edition 13.2-3.
CWE description: The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
CVSS v3 base score: 7.2
Published: 2021-12-15T20:15Z
Repository: https://github.com/Enalean/tuleap
Language: PHP
Files changed: plugins/ldap/include/LDAP_DirectorySynchronization.class.php, src/common/DB/Compat/Legacy2018/LegacyDataAccessInterface.php
Commit date: 2021-11-17 16:46:33 +0100
Commit message: request #24149: Indirect LDAP injection via the ldap_id attribute of a user

A taint annotation has been added to hightlight the issue. A more global
work on this topic will be done in independant contributions.

Change-Id: I969d0ba6d2ff85b418bcaf728f49afc78dd49571

Diff: diff --git a/plugins/ldap/include/LDAP_DirectorySynchronization.class.php b/plugins/ldap/include/LDAP_DirectorySynchronization.class.php
index b9b6ea95c7d..a087f2a4e90 100755
--- a/plugins/ldap/include/LDAP_DirectorySynchronization.class.php
+++ b/plugins/ldap/include/LDAP_DirectorySynchronization.class.php
@@ -74,11 +74,11 @@ class LDAP_DirectorySynchronization
         }
     }
 
     public function ldapSync($row, $users_are_suspendable = true)
     {
-        $ldap_query = $this->ldap->getLDAPParam('eduid') . '=' . $row['ldap_id'];
+        $ldap_query = $this->ldap->getLDAPParam('eduid') . '=' . ldap_escape($row['ldap_id'], '', LDAP_ESCAPE_FILTER);
         $userSync   = $this->getLdapUserSync();
         $attributes = $userSync->getSyncAttributes($this->ldap);
 
         $time_start = microtime(true);
         $lri        = false;
diff --git a/src/common/DB/Compat/Legacy2018/LegacyDataAccessInterface.php b/src/common/DB/Compat/Legacy2018/LegacyDataAccessInterface.php
index c703bedf21d..00e584b8c77 100644
--- a/src/common/DB/Compat/Legacy2018/LegacyDataAccessInterface.php
+++ b/src/common/DB/Compat/Legacy2018/LegacyDataAccessInterface.php
@@ -175,10 +175,11 @@ interface LegacyDataAccessInterface
      *
      * @deprecated since version 4.0
      * @param type $result
      *
      * @return type
+     * @psalm-taint-source ldap
      */
     public function fetchArray($result);
 
     /**
      * Move internal result pointer

Vulnerable code:         $ldap_query = $this->ldap->getLDAPParam('eduid') . '=' . $row['ldap_id'];
Fixed code:         $ldap_query = $this->ldap->getLDAPParam('eduid') . '=' . ldap_escape($row['ldap_id'], '', LDAP_ESCAPE_FILTER);
     * @psalm-taint-source ldap