HIGH ldap injectionexpressbasic auth

Ldap Injection in Express with Basic Auth

Ldap Injection in Express with Basic Auth — how this specific combination creates or exposes the vulnerability

LDAP Injection occurs when an attacker can manipulate LDAP query construction through untrusted input. In an Express application that uses LDAP for authentication with HTTP Basic Auth, the combination of extracting credentials from the Authorization header and building an LDAP filter or DN from those values creates a path for injection if input validation is absent.

Consider an implementation that takes the user-provided username from the Basic Auth header and concatenates it into an LDAP search filter or DN without sanitization. An attacker can supply a username such as (uid=* or )(uid=admin)(uid=* to alter the intended filter logic. Because the search base and filter are built dynamically, the injected syntax can change the scope or matching criteria, potentially returning other user entries or bypassing intended constraints. Even when authentication ultimately binds with the constructed DN, malicious input can lead to over-privileged searches or information disclosure, which may be surfaced indirectly through timing or error messages.

Because middleBrick scans the unauthenticated attack surface, patterns like these are detectable: it performs input validation checks that look for improper handling of user-controlled data in authentication-related endpoints. The tool also includes checks aligned with OWASP API Top 10 and relevant mappings for authentication and authorization flaws, helping to highlight risks where dynamic LDAP query construction intersects with external input.

Basic Auth-Specific Remediation in Express — concrete code fixes

To secure Express endpoints that rely on HTTP Basic Auth and LDAP, avoid building LDAP DNs or filters by string concatenation with raw user input. Instead, treat the username as an identity to be bound or to parameterize a controlled filter, and use strict allow-lists for acceptable characters. Below are two approaches with runnable Express snippets.

Approach 1: Bind-based authentication with parameterized DN. Resolve the user’s DN through a safe mapping (e.g., an internal directory or database) and then attempt a bind. This eliminates injection risk to the search step because the DN is constructed from a trusted mapping rather than direct input.

const express = require('express');
const basicAuth = require('express-basic-auth');
const { ldapClient } = require('./ldap-client'); // configured ldap client

const app = express();

// In-memory user-to-DN map for example; in production this may be a controlled lookup service
const userToDn = {
  alice: 'uid=alice,ou=people,dc=example,dc=com',
  bob: 'uid=bob,ou=people,dc=example,dc=com'
};

app.get('/profile',
  basicAuth({
    challenge: true,
    authorizer: (username, password) => {
      const dn = userToDn[username];
      if (!dn) {
        return false;
      }
      return ldapClient.authenticate(dn, password);
    }
  }),
  (req, res) => {
    res.json({ user: req.auth.user, message: 'Authenticated' });
  }
);

app.listen(3000, () => console.log('Server running on port 3000'));

Approach 2: Parameterized search with strict input validation. If you must perform a search, validate the username against a strict pattern (alphanumeric plus limited symbols), use a parameterized filter, and avoid concatenating the username into the filter string.

const express = require('express');
const basicAuth = require('express-basic-auth');
const { ldapClient } = require('./ldap-client');

const app = express();

const isValidUsername = (username) => {
  // Allow only letters, digits, underscore, hyphen; prevent special LDAP characters
  return /^[a-zA-Z0-9_\-]+$/.test(username);
};

app.get('/search',
  basicAuth({
    challenge: true,
    authorizer: (username, password) => {
      if (!isValidUsername(username)) {
        return false;
      }
      const filter = '(uid=*)';
      const searchOptions = {
        filter: `(&(uid=${username})(objectClass=inetOrgPerson))`, // username inserted in a controlled way
        scope: 'sub',
        attributes: ['uid', 'mail']
      };
      // Example ldapClient.search usage; actual implementation depends on your LDAP client
      return ldapClient.searchAndBind(username, password, searchOptions);
    }
  }),
  (req, res) => {
    res.json({ user: req.auth.user, message: 'Search succeeded' });
  }
);

app.listen(3000, () => console.log('Server running on port 3000'));

Additional remediation guidance includes using environment-based configuration for connection parameters, enforcing TLS for LDAP traffic, and applying the principle of least privilege to the LDAP service account used for binding. These measures reduce the impact of any residual misconfiguration and align with secure authentication patterns recommended for production services.

Frequently Asked Questions

Why does using the raw username in an LDAP filter or DN make Express applications vulnerable to LDAP Injection?
Because special LDAP syntax characters (such as *, (, ), &, |) can change query semantics when concatenated directly. An attacker can inject filter components or manipulate the DN structure, leading to unauthorized data retrieval or privilege escalation.
Does middleBrick detect LDAP Injection risks in Express APIs using Basic Auth?
middleBrick tests authentication and input validation controls as part of its 12 parallel security checks. It identifies insecure handling of user input in authentication flows and provides findings with severity ratings and remediation guidance, though it does not fix or block issues.