projectdiscovery/nuclei · error

unsupported ldap url schema %v

Error message

unsupported ldap url schema %v

What it means

Thrown by the ldap.Client constructor when the URL scheme is not one of ldap, ldaps, ldapi or cldap. An empty scheme defaults to ldap, so this error only fires for a genuinely different scheme token after url.Parse lowercases it.

Source

Thrown at pkg/js/libs/ldap/ldap.go:142

				conn, err = dialers.Fastdialer.Dial(dialCtx, "udp", net.JoinHostPort(host, port))
			case "ldap":
				if port == "" {
					port = ldap.DefaultLdapPort
				}
				conn, err = dialers.Fastdialer.Dial(dialCtx, "tcp", net.JoinHostPort(host, port))
			case "ldaps":
				if port == "" {
					port = ldap.DefaultLdapsPort
				}
				serverName := host
				if c.cfg.ServerName != "" {
					serverName = c.cfg.ServerName
				}
				conn, err = dialers.Fastdialer.DialTLSWithConfig(dialCtx, "tcp", net.JoinHostPort(host, port),
					&tls.Config{InsecureSkipVerify: true, MinVersion: tls.VersionTLS10, ServerName: serverName})
			}
		default:
			err = fmt.Errorf("unsupported ldap url schema %v", u.Scheme)
		}
		c.nj.HandleError(err, "failed to connect to ldap server")
	}
	c.conn = ldap.NewConn(conn, u.Scheme == "ldaps")
	if u.Scheme != "ldaps" && c.cfg.Upgrade {
		serverName := u.Hostname()
		if c.cfg.ServerName != "" {
			serverName = c.cfg.ServerName
		}
		if err := c.conn.StartTLS(&tls.Config{InsecureSkipVerify: true, ServerName: serverName}); err != nil {
			c.nj.HandleError(err, "failed to upgrade to tls")
		}
	} else {
		c.conn.Start()
	}

	return utils.LinkConstructor(call, runtime, c)
}

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Use one of the four supported prefixes: ldap://, ldaps:// (TLS), ldapi:// (unix socket), cldap:// (UDP, deprecated CLDAP)
  2. For Global Catalog, use ldap://host:3268 or ldaps://host:3269 — the TDS/LDAP wire protocol is the same
  3. Drop the scheme entirely to default to plain ldap://

Example fix

// before
const c = new ldap.Client('gc://dc01.acme.local:3268', 'ACME'); // unsupported schema gc

// after
const c = new ldap.Client('ldap://dc01.acme.local:3268', 'ACME');
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = ['ldap', 'ldaps', 'ldapi', 'cldap'];
const scheme = ldapUrl.split(':')[0].toLowerCase();
const url = (scheme === '' || ALLOWED.includes(scheme)) ? ldapUrl : 'ldap://' + ldapUrl.replace(/^[a-zA-Z0-9+.-]+:\/\//, '');
const client = new ldap.Client(url, realm);

Type guard

const isSupportedLdapUrl = (u) => {
  const s = u.split(':')[0].toLowerCase();
  return s === '' || ['ldap','ldaps','ldapi','cldap'].includes(s);
};

Prevention

When it happens

Trigger: new ldap.Client('gc://dc01:3268', 'ACME') (Global Catalog), 'http://...', 'ldap3://...'; also copy-pasted Windows LDP strings with unusual prefixes. Note 'GC://' parses to scheme 'gc' and hits this branch.

Common situations: Using the AD Global Catalog port URI gc:// out of habit from PowerShell/AD tooling; typos in the scheme; forgetting that ldapi is the Unix-socket scheme and inventing variants like 'ldaps+unix://'.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/16e4b3778a4124a4. Report an issue: GitHub.