java.lang.security.audit.ldap-injection.ldap-injection

Community Favorite
profile photo of semgrepsemgrep
Author
73,396
Download Count*

Detected non-constant data passed into an LDAP query. If this data can be controlled by an external user, this is an LDAP injection. Ensure data passed to an LDAP query is not controllable; or properly sanitize the data.

Run Locally

Run in CI

Defintion

rules:
  - id: ldap-injection
    message: Detected non-constant data passed into an LDAP query. If this data can
      be controlled by an external user, this is an LDAP injection. Ensure data
      passed to an LDAP query is not controllable; or properly sanitize the
      data.
    metadata:
      cwe:
        - "CWE-90: Improper Neutralization of Special Elements used in an LDAP
          Query ('LDAP Injection')"
      owasp:
        - A01:2017 - Injection
        - A03:2021 - Injection
      source-rule-url: https://find-sec-bugs.github.io/bugs.htm#LDAP_INJECTION
      asvs:
        section: "V5: Validation, Sanitization and Encoding Verification Requirements"
        control_id: 5.3.7 Injection
        control_url: https://github.com/OWASP/ASVS/blob/master/4.0/en/0x13-V5-Validation-Sanitization-Encoding.md#v53-output-encoding-and-injection-prevention-requirements
        version: "4"
      category: security
      technology:
        - java
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      subcategory:
        - audit
      likelihood: LOW
      impact: HIGH
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - LDAP Injection
    severity: WARNING
    languages:
      - java
    patterns:
      - pattern-either:
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                InitialDirContext $CTX = ...;
                ...
              }
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                DirContext $CTX = ...;
                ...
              }
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                InitialLdapContext $CTX = ...;
                ...
              }
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                LdapContext $CTX = ...;
                ...
              }
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                LdapCtx $CTX = ...;
                ...
              }
          - pattern-inside: |
              $X $METHOD(...) {
                ...
                EventDirContext $CTX = ...;
                ...
              }
      - pattern: |
          $X $METHOD(...) {
            ...
            $CTX.search($Y,$INPUT,...);
            ...
          }
      - pattern-not: |
          $X $METHOD(...) {
            ...
            $CTX.search($Y,"...",...);
            ...
          }

Examples

ldap-injection.java

package testcode.ldap;

import com.sun.jndi.ldap.LdapCtx;
import javax.naming.Context;
import javax.naming.InvalidNameException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.event.EventDirContext;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.LdapName;
import java.util.Properties;

public class JndiLdapAdditionalSignature {

    // ruleid: ldap-injection
    public static void moreLdapInjections(String input) throws NamingException {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
        props.put(Context.REFERRAL, "ignore");

        SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[]{"givenName", "sn"});
        ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        DirContext context1 = new InitialDirContext(props);

        NamingEnumeration<SearchResult> answers;
        answers = context1.search(new LdapName("dc=People,dc=example,dc=com"), "(uid=" + input + ")", ctrls);
    }

    // ruleid: ldap-injection
    public static void moreLdapInjections1(String input) throws NamingException {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
        props.put(Context.REFERRAL, "ignore");

        SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[]{"givenName", "sn"});
        ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        InitialDirContext context2 = new InitialDirContext(props);

        NamingEnumeration<SearchResult> answers;
        answers = context2.search(new LdapName("dc=People,dc=example,dc=com"), "(uid=" + input + ")", new Object[0], ctrls);
    }

    // ruleid: ldap-injection
    public static void moreLdapInjections2(String input) throws NamingException {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
        props.put(Context.REFERRAL, "ignore");

        SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[]{"givenName", "sn"});
        ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        InitialLdapContext context3 = new InitialLdapContext();
        LdapContext        context4 = new InitialLdapContext();

        NamingEnumeration<SearchResult> answers;
        answers = context3.search("dc=People,dc=example,dc=com", "(uid=" + input + ")", ctrls);
    }

    // ruleid: ldap-injection
    public static void moreLdapInjections3(String input) throws NamingException {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
        props.put(Context.REFERRAL, "ignore");

        SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[]{"givenName", "sn"});
        ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        LdapContext context4 = new InitialLdapContext();

        NamingEnumeration<SearchResult> answers;
        answers = context4.search("dc=People,dc=example,dc=com", "(uid=" + input + ")", new Object[0], ctrls);
    }

    // ruleid: ldap-injection
    public void ldapInjectionSunApi5(String input) throws NamingException {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
        props.put(Context.REFERRAL, "ignore");

        SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[]{"givenName", "sn"});
        ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        LdapCtx context5 = new InitialDirContext(props);

        NamingEnumeration<SearchResult> answers;
        answers = context5.search("dc=People,dc=example,dc=com", "(uid=" + input + ")", new Object[0], ctrls);
    }

    // ruleid: ldap-injection
    public void ldapInjectionSunApi6(String input) throws NamingException {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
        props.put(Context.REFERRAL, "ignore");

        SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[]{"givenName", "sn"});
        ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        EventDirContext context6 = new InitialDirContext(props);

        NamingEnumeration<SearchResult> answers;
        answers = context6.search("dc=People,dc=example,dc=com", "(uid=" + input + ")", new Object[0], ctrls);
    }

    // ok: ldap-injection
    public static void moreLdapInjections4(String input) throws NamingException {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
        props.put(Context.REFERRAL, "ignore");

        SearchControls ctrls = new SearchControls();
        ctrls.setReturningAttributes(new String[]{"givenName", "sn"});
        ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        DirContext context1 = new InitialDirContext(props);

        NamingEnumeration<SearchResult> answers;
        //False positive
        answers = context1.search(new LdapName("dc=People,dc=example,dc=com"), "(uid=bob)", new Object[0], ctrls);
    }


}