Neutron, our AI engine, scored 97.1% on UC Berkeley's CyberGym benchmark. Learn more

Deep Dive

Deep Dive

Traccar LDAP Auth Bypass via Empty Password (CVE-2026-126777)

Traccar 3.15 through 6.16.0 accepts an empty password on LDAP logins, so an attacker who knows a username can sign in as any user, including administrators.

TL;DR

  • Traccar sends an empty LDAP password to the directory and treats the resulting unauthenticated bind as a successful login. VulnCheck published the flaw as CVE-2026-126777 on November 11, 2026.
  • Every Traccar release from 3.15 through 6.16.0 is affected when LDAP authentication is enabled and the directory accepts unauthenticated binds.
  • The score is CVSS v4.0 9.1 Critical and CVSS v3.1 7.4 High. No exploitation is known, and the CVE is not in CISA KEV as of November 12, 2026.
  • Upgrade to 6.17.0, released on November 1, 2026. If you cannot, disable LDAP authentication or block access to the session endpoint until you can.

Am I affected?

You are exposed if all four of these conditions hold:

  • You run Traccar 3.15 through 6.16.0.
  • LDAP authentication is configured. Traccar creates its LDAP provider when the ldap.url setting is present.
  • The LDAP directory accepts an unauthenticated bind for a known account name. Directories that reject a zero-length password are not exploitable this way.
  • The attacker knows a valid account name, such as an email address or login.

The flaw is in the login path, so it affects the web API and any client that uses HTTP Basic authentication. It does not depend on the Traccar web interface. An account that is an administrator is as exposed as any other account.

The ldap.force setting decides whether every login uses LDAP or whether LDAP is tried alongside local accounts. A deployment with ldap.force off can still be attacked through any account name that exists in the directory.

Branch Affected versions Fixed version
All releases 3.15 through 6.16.0 6.17.0, released 2026-11-01

Traccar's server endpoint reports the running version without authentication:

curl -s https://<traccar-host>/api/server | python3 -c "import json,sys; print(json.load(sys.stdin)['version'])"

Confirm that LDAP is enabled by checking the configuration file inside the container or the installation directory:

docker exec traccar sh -c 'grep -n "ldap\." /opt/traccar/conf/traccar.xml'

The same settings appear in the traccar.xml file of a package installation. A deployment without ldap.url does not use the vulnerable provider.

How do I fix it?

Upgrade to Traccar 6.17.0. The release contains the three-line check that rejects a null or empty password before the directory bind starts.

  1. Set the image tag in your compose file to traccar/traccar:6.17.0, then pull the image and recreate the container. A compose file that still references another tag keeps the vulnerable image running: docker pull traccar/traccar:6.17.0 docker compose up -d
  2. Confirm the running version: curl -s https://<traccar-host>/api/server | python3 -c "import json,sys; print(json.load(sys.stdin)['version'])"
  3. For a package installation, download the 6.17.0 release, stop the service, replace the program files and start it again.
  4. Test one LDAP login with a correct password and one with an empty password. The empty-password attempt must now fail.

If you cannot update immediately, reduce exposure with these measures. None replaces the patch.

  1. Remove the ldap.url setting to turn LDAP authentication off, and keep at least one local administrator account that you can use. Traccar falls back to its local user store.
  2. Restrict /api/session and HTTP Basic authentication to trusted networks at the proxy. This closes the remote login path but does not fix the missing password check.
  3. Disable the accounts that LDAP would authenticate if you do not need them during the window. An attacker still needs a valid account name, so removing the name removes the path.

What is the root cause?

LdapProvider.login() accepts any password, including an empty string, and uses the directory's answer as proof that the password was correct.

The method looks up the account first, then binds as that account with the supplied password:

    public boolean login(String username, String password) {
        try {
            SearchResult ldapUser = lookupUser(username);
            if (ldapUser != null) {
                auth(ldapUser.getNameInNamespace(), password).close();
                return true;
            }
        } catch (NamingException e) {
            return false;
        }
        return false;
    }

lookupUser runs with the service account. It returns the distinguished name of the requested account. The bind then uses the attacker-supplied password:

    private InitialDirContext auth(String accountName, String password) throws NamingException {
        Hashtable<String, String> env = new Hashtable<>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, url);

        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, accountName);
        env.put(Context.SECURITY_CREDENTIALS, password);

        return new InitialDirContext(env);
    }

Java's JNDI sends a simple bind with the distinguished name and the password. When the password is empty, the request carries a zero-length credential. RFC 4513 defines this as an unauthenticated bind, and a directory may accept it and return a success result. Traccar never checks that the result came from a password-authenticated bind, so it returns true.

The lookup is what makes the attack precise: the attacker does not need to guess a password or a distinguished name, only a valid account name.

How is it exploited?

  1. The attacker sends a login request to POST /api/session with a valid account name and an empty password.
  2. Traccar calls LdapProvider.login() with that name and the empty password.
  3. lookupUser() uses the service account to find the account's distinguished name in the directory.
  4. auth() sends a simple bind with that distinguished name and a zero-length password.
  5. A directory that permits unauthenticated binds returns a context. Traccar treats the context as a successful password check.
  6. Traccar creates a session for the account, including an administrator account if the name belongs to one.

The same path is reachable with HTTP Basic authentication, which uses the same login service. No public proof-of-concept code is published, and the request needs no special tooling.

How does the attack flow?

A valid account name and an empty password reach an LDAP bind that the directory answers without checking a password, and Traccar accepts that answer as a login.

flowchart LR A["POST /api/session with
a valid name and empty password"] --> B["LdapProvider.login()"] B --> C["lookupUser() finds the
account distinguished name"] C --> D["JNDI simple bind with
no password check"] D --> E["Directory performs an
unauthenticated bind"] E --> F["Session issued for
the target account"]

What can an attacker do?

An attacker who knows an administrator account name gets an administrator session without a password. A Traccar administrator sees the live position, route history, event reports and maintenance records for every device, and can list and manage every user, device, geofence, notification and saved report. The administrator can also send commands to devices that support them, which can immobilize a vehicle or change its configuration.

A session for a non-administrator account gives that account's devices and positions. In a fleet deployment, that can still expose live location data for many vehicles. A read-only operator account exposes the same location history for the devices it can see, which is still sensitive fleet data.

The flaw gives no code execution on the server by itself. The impact is the account's permissions, and the administrator account is the one that matters. The attacker needs network access to the login endpoint and one valid account name. No user interaction is required.

Why does the fix work?

The fix rejects a null or empty password before any lookup or bind:

     public boolean login(String username, String password) {
+        if (password == null || password.isEmpty()) {
+            return false;
+        }
         try {
             SearchResult ldapUser = lookupUser(username);
             if (ldapUser != null) {

The check runs before lookupUser, so an empty password cannot reach the directory at all. A non-empty password still takes the normal simple-bind path. The directory then decides whether the credential is correct, and Traccar only accepts a context that the directory returned for that credential.

The fix is complete for this path. Traccar uses the same auth() method for its service-account lookups, and those calls pass a configured service password. A deployment that sets an empty service password would still perform an unauthenticated service bind, so keep that setting non-empty as well.

How do I check if I was compromised?

There are no published indicators for this CVE. Check the directory and the Traccar access logs for the pattern:

  • Simple binds from the Traccar service host with a zero-length password.
  • Successful sessions for administrator accounts from addresses that do not match the operator's usual locations.
  • POST /api/session requests in the reverse-proxy access log from client addresses outside your trusted ranges. Access logs record the path and the client address, not the request body, so the password field itself is not visible.

A directory that accepts unauthenticated binds may log the bind as anonymous or as a normal bind, depending on its configuration. A failed attempt may leave no entry at all. Treat an unexpected administrator session as a compromise and rotate the account password and any API tokens the account can reach.

Timeline

  • 2026-10-31: The fix commit 552c31f2 adds the empty-password check.
  • 2026-11-01: Traccar 6.17.0 is released with the fix.
  • 2026-11-11: VulnCheck publishes CVE-2026-126777 at 18:41 UTC.

The fix was committed 11 days before the CVE record appeared: one day from the commit to the release, and 10 days from the release to the disclosure.

The fix was committed 11 days before the CVE record
Figure 1: The fix was committed 11 days before the CVE. Source: Traccar commit 552c31f2, the 6.17.0 release and the CVE record, checked November 12, 2026

FAQ

Does this affect every Traccar deployment?

No. The deployment must use LDAP authentication, and the directory must accept an unauthenticated bind for the account name. A Traccar instance with only local accounts is not affected.

Can I test my directory safely?

Yes, with a test account and a controlled client. Send a simple bind with a valid distinguished name and a zero-length password, and check whether the directory returns success. Do not test against a production administrator account.

Why does an empty password count as a login?

LDAP defines a bind with a name and a zero-length password as an unauthenticated bind. Some directories accept it to support anonymous-style access. Traccar did not distinguish that result from a password-authenticated bind.

Is the web interface required?

No. The same login service handles the web interface, POST /api/session and HTTP Basic authentication. Any client that can reach the login endpoint can use the flaw.

Does ldap.force change the exposure?

No. The setting changes which accounts use LDAP, not whether the empty-password bind is accepted. An account that exists in the directory can be used through the LDAP path even when local login is also enabled.

Does 6.17.0 change anything else?

The 6.17.0 release contains the empty-password check and its usual feature and fix set. The security-relevant change is the three-line guard in LdapProvider.login().

Does the fix break normal LDAP logins?

No. A non-empty password still goes through the same simple bind against the directory. The fix only rejects a null or empty password before the bind, so users who type a password see no change.

Should I rotate passwords?

Yes, if an administrator session may have been created without a password. Rotate the affected account password and review the account's recent actions. A directory that accepted an unauthenticated bind did not verify the attacker, so the password itself was not exposed, but the session was.

References

  • VulnCheck advisory for CVE-2026-126777, https://www.vulncheck.com/advisories/traccar-3.15-before-6.17.0-authentication-bypass-via-empty-ldap-password (checked November 12, 2026).
  • CVE-2026-126777 record, https://www.cve.org/CVERecord?id=CVE-2026-126777 (checked November 12, 2026).
  • Traccar fix commit 552c31f2, https://github.com/traccar/traccar/commit/552c31f2097dbed9edef7cfe174c50b16febdc21 (checked November 12, 2026).
  • Traccar 6.17.0 release, https://github.com/traccar/traccar/releases/tag/v6.17.0 (checked November 12, 2026).
  • Traccar v6.16.0 LdapProvider.java, https://github.com/traccar/traccar/blob/v6.16.0/src/main/java/org/traccar/database/LdapProvider.java (checked November 12, 2026).
  • Traccar v6.17.0 LdapProvider.java, https://github.com/traccar/traccar/blob/v6.17.0/src/main/java/org/traccar/database/LdapProvider.java (checked November 12, 2026).
  • RFC 4513, section 5.1.2, Unauthenticated Bind Operation, https://www.rfc-editor.org/rfc/rfc4513#section-5.1.2 (checked November 12, 2026).
  • Traccar repository, https://github.com/traccar/traccar (checked November 12, 2026).
  • CISA Known Exploited Vulnerabilities catalog, https://www.cisa.gov/known-exploited-vulnerabilities-catalog (checked November 12, 2026).