The 'NTLM authentication failed' error occurs when Git cannot authenticate through a corporate proxy server using NTLM (NT LAN Manager) credentials. The reliable professional fix is to run a local authenticating proxy (CNTLM or Px) that handles the NTLM handshake using hashed or SSO credentials, rather than embedding plaintext passwords in Git config.
This error indicates that Git's underlying HTTP library (libcurl) failed to authenticate with an NTLM-based proxy server. NTLM is a Microsoft authentication protocol commonly used in corporate networks to authenticate users against a Windows domain before allowing internet access. When you run Git commands that need network access (clone, push, pull, fetch), Git must communicate through your corporate proxy. If the proxy uses NTLM authentication, Git needs to perform a multi-step challenge-response handshake, providing your Windows domain credentials in a specific encrypted format. Git's libcurl-based NTLM support is fragile and version-dependent, which is why a dedicated local proxy is the recommended fix. The authentication failure can occur for several reasons: 1. Git/libcurl NTLM support limitations - not all Git builds fully support NTLM proxy auth. 2. Credential issues - incorrect domain, username, or password, or wrong escaping of the DOMAIN\username form. 3. Proxy configuration - incorrect proxy URL or authentication method. 4. Network policy - the proxy may require NTLMv2, Kerberos/Negotiate, or MITM TLS decryption with a corporate CA. This is a common problem in enterprise environments where network security policies require all HTTP/HTTPS traffic to pass through an authenticated proxy server.
CNTLM (Cntlm Authentication Proxy) is the most reliable solution for NTLM proxy authentication and is the recommended approach. It runs as a local proxy that performs the NTLM handshake on your behalf using a hashed password, so your plaintext password never lives in Git config or environment variables.
Step 1: Install CNTLM
- Windows: Download from [cntlm.sourceforge.net](https://cntlm.sourceforge.net/) or install via Chocolatey:
choco install cntlm- macOS:
brew install cntlm- Linux (Debian/Ubuntu):
sudo apt-get install cntlmStep 2: Generate a password hash (do NOT store the plaintext password)
cntlm -H -d YOUR_DOMAIN -u YOUR_USERNAME
# Enter your password when prompted; it is used only to compute the hash.
# Copy the PassNTLMv2 value from the output.Step 3: Configure cntlm.ini (Windows) or /etc/cntlm.conf (Linux/macOS)
Username your_username
Domain YOUR_DOMAIN
Proxy corporate-proxy.company.com:8080
NoProxy localhost, 127.0.0.*, 10.*, 192.168.*
# Bind to localhost only so other machines cannot use your proxy
Listen 127.0.0.1:3128
# Paste the hash from step 2 - never put a plaintext Password line here
PassNTLMv2 ABC123...Step 4: Start CNTLM
# Windows (as service)
net start cntlm
# Linux/macOS
sudo cntlm -c /etc/cntlm.conf
# Or run in foreground for testing
cntlm -fStep 5: Point Git at CNTLM
git config --global http.proxy http://127.0.0.1:3128
git config --global https.proxy http://127.0.0.1:3128Important: Use 127.0.0.1 instead of localhost to avoid DNS resolution delays, and never commit your hash to a shared repo.
Px is a modern alternative to CNTLM that leverages Windows SSPI for automatic authentication. It is the best choice on a domain-joined Windows machine because it uses your existing logon session via SSPI - no password or hash is stored anywhere.
Install Px:
# Using pip
pip install px-proxy
# Or download the standalone executable from GitHub releases:
# https://github.com/genotrance/px/releasesRun Px:
# Start Px (auto-detects your proxy from Windows settings via SSPI)
px
# Or specify the upstream proxy
px --proxy=corporate-proxy.company.com:8080
# Run on a specific port
px --listen=3128Point Git at Px:
git config --global http.proxy http://127.0.0.1:3128
git config --global https.proxy http://127.0.0.1:3128Advantages of Px:
- Uses Windows single sign-on (SSPI) - no password or hash storage needed.
- Automatically detects proxy settings from Windows / PAC files.
- Supports both NTLM and Kerberos/Negotiate authentication.
- No configuration file needed in most cases.
Git 1.7.10+ has native NTLM support through libcurl, but it is version-dependent and fragile. Prefer the CNTLM/Px approach above; use direct config only as a fallback. Do not embed a plaintext password in `http.proxy` or environment variables - let Git prompt and store it in a credential helper instead.
Recommended: set the proxy host and auth method only, no password
# Configure the proxy WITHOUT credentials; Git/curl will prompt and the
# credential helper (manager-core / osxkeychain / libsecret) caches it securely.
git config --global http.proxy http://proxy.company.com:8080
git config --global http.proxyauthmethod ntlm
# Make sure a secure credential helper is configured
# Windows:
git config --global credential.helper manager-core
# macOS:
git config --global credential.helper osxkeychain
# Linux:
git config --global credential.helper libsecretEscaping the domain/username (when a username is required)
The reliable, cross-version way to express DOMAIN\username and special characters is URL-encoding them. Use this form first:
# PRIMARY (reliable): URL-encode the backslash as %5C and @ as %40, etc.
# DOMAIN\username -> DOMAIN%5Cusername
git config --global http.proxy http://DOMAIN%[email protected]:8080# FALLBACK (version-dependent, often misbehaves): a literal backslash.
# Shell + Git config double-escaping makes the exact backslash count
# unreliable across platforms, so avoid this unless URL-encoding fails.
git config --global http.proxy "http://DOMAIN\[email protected]:8080"Note: omit the :password portion entirely so no plaintext secret is written to ~/.gitconfig.
Choose the proxy authentication method explicitly
# Pure NTLM
git config --global http.proxyauthmethod ntlm
# Negotiate (Kerberos with NTLM fallback) - best on domain-joined machines
git config --global http.proxyauthmethod negotiate
# Basic (only if the proxy actually supports it)
git config --global http.proxyauthmethod basicEmpty credentials for Windows integrated auth
# On Windows, empty credentials may trigger SSPI/integrated auth
git config --global http.proxy http://:@proxy.company.com:8080/Many corporate proxies decrypt HTTPS (a deliberate man-in-the-middle) and re-sign traffic with an internal CA. Git then reports certificate errors because it does not trust that CA. The correct fix is to trust the corporate CA - never disable TLS verification, since `http.sslVerify false` on a MITM-decrypting proxy strips the only protection you have and exposes every credential and clone over that link.
Recommended: import the corporate CA certificate
# Obtain the proxy/root CA PEM from your IT team, then point Git at it:
git config --global http.sslCAInfo /path/to/corp-ca.pem
# To scope it to just the proxied host instead of globally:
git config --global http."https://github.com/".sslCAInfo /path/to/corp-ca.pemYou can also append the CA to Git's bundled CA file (location varies by install), but a dedicated http.sslCAInfo path is cleaner and easier to maintain.
On Windows: use the schannel backend so Git trusts the OS certificate store
# schannel uses the Windows certificate store, where IT usually deploys the
# corporate CA automatically via group policy - no PEM file needed.
git config --global http.sslBackend schannelThis is the cleanest option on managed Windows machines and also tends to interoperate better with NTLM/Negotiate proxies.
Strongly discouraged
# DO NOT do this on a corporate MITM proxy - it disables certificate
# validation entirely and makes you trivially impersonatable.
# git config --global http.sslVerify false # <-- avoidIf a debugging proxy such as Fiddler/mitmproxy is involved, import that tool's root certificate the same way (http.sslCAInfo) instead of turning verification off, and scope it to a temporary config you remove afterward.
NTLM proxy support has improved in newer Git versions. Ensure you are running a recent build:
Check your Git version:
git --versionGit NTLM support timeline:
- Git 1.7.10+ - initial NTLM proxy support via libcurl
- Git 2.14+ - improved proxy authentication handling
- Git 2.26+ - better credential helper integration
Update Git:
# Windows: self-update
git update-git-for-windows
# or download the latest from https://git-scm.com/download/win
# macOS
brew upgrade git
# Linux (Ubuntu/Debian) - latest stable
sudo add-apt-repository ppa:git-core/ppa
sudo apt update
sudo apt install gitCheck / choose the SSL backend:
# See what backend Git is using
git config --global http.sslBackend
# On Windows, schannel uses the native Windows cert store and often
# works best with corporate proxies (NTLM + corporate CA trust)
git config --global http.sslBackend schannel
# Or OpenSSL if you prefer a PEM-based CA bundle (see http.sslCAInfo)
git config --global http.sslBackend opensslNTLMAPS (NTLM Authorization Proxy Server) is an older Python-based NTLM proxy. Prefer CNTLM or Px; use NTLMAPS only if neither is available. Note that NTLMAPS stores the plaintext password in its config, so restrict file permissions and rotate the password if it leaks.
Install NTLMAPS:
wget https://downloads.sourceforge.net/project/ntlmaps/ntlmaps/ntlmaps-0.9.9.0.1/ntlmaps-0.9.9.0.1.tar.gz
tar xzf ntlmaps-0.9.9.0.1.tar.gz
cd ntlmaps-0.9.9.0.1Configure server.cfg (plaintext password - NOT recommended; lock down the file):
LISTEN_PORT:5865
PARENT_PROXY:corporate-proxy.company.com
PARENT_PROXY_PORT:8080
NT_DOMAIN:YOUR_DOMAIN
USER:your_username
# PASSWORD stored in plaintext here - prefer CNTLM hash or Px SSPI instead
PASSWORD:your_passwordchmod 600 server.cfgStart NTLMAPS:
python main.pyPoint Git at it:
git config --global http.proxy http://127.0.0.1:5865
git config --global https.proxy http://127.0.0.1:5865Note: NTLMAPS is older and less maintained than CNTLM. Use CNTLM (hashed credentials) or Px (SSPI) whenever possible.
Enable verbose output to understand exactly where authentication is failing:
Enable Git HTTP debugging:
# Full HTTP/curl tracing
GIT_CURL_VERBOSE=1 git clone https://github.com/user/repo.git
# General Git tracing
GIT_TRACE=1 git clone https://github.com/user/repo.git
# Everything combined, saved to a log
GIT_TRACE=1 GIT_CURL_VERBOSE=1 GIT_TRACE_PACKET=1 git clone https://github.com/user/repo.git 2>&1 | tee git-debug.logInspect current proxy / HTTP config:
git config --global --list | grep -i proxy
git config --global --list | grep -i httpTest proxy connectivity with curl:
# Test NTLM auth via curl. Prefer letting curl prompt rather than embedding a password.
curl -v --proxy http://proxy.company.com:8080 --proxy-ntlm -U "DOMAIN\username" https://github.com
# Empty auth (Windows integrated / SSPI)
curl -v --proxy http://proxy.company.com:8080 --proxy-ntlm -U ":" https://github.comCommon debug output clues:
- 407 Proxy Authentication Required - credentials not accepted
- Connection timed out - proxy address or port incorrect
- SSL certificate problem / unable to get local issuer certificate - corporate MITM CA not trusted (see the CA-import step)
- NTLM handshake failed - domain or credential format issue
Stale credentials can cause persistent authentication failures:
Clear Git proxy configuration:
git config --global --unset http.proxy
git config --global --unset https.proxy
git config --global --unset http.proxyauthmethod
# Verify
git config --global --list | grep proxyClear stored credentials (Windows Credential Manager):
# List credentials
cmdkey /list
# Delete the proxy/host entry
cmdkey /delete:targetname
# Or open the GUI
control /name Microsoft.CredentialManagerClear Git credential helper cache:
# For the manager / store helpers, you can also erase via:
printf 'protocol=https\nhost=github.com\n' | git credential rejectClear environment variables that may override config:
echo $HTTP_PROXY; echo $HTTPS_PROXY; echo $http_proxy; echo $https_proxy
unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxyReset CNTLM after a password change (regenerate the hash, never store plaintext):
cntlm -H -d YOUR_DOMAIN -u YOUR_USERNAME
# Update the PassNTLMv2 hash in cntlm.conf, then restart CNTLM### Understanding the NTLM Authentication Flow
NTLM is a challenge-response protocol with three steps:
1. Type 1 (Negotiate) - client sends the initial request to the proxy.
2. Type 2 (Challenge) - proxy responds with a challenge containing server info.
3. Type 3 (Authenticate) - client responds with credentials derived from the challenge.
If any step fails, you get the 'NTLM authentication failed' error.
### NTLMv1 vs NTLMv2
Modern corporate environments typically require NTLMv2:
cntlm -H -d DOMAIN -u username
# Use the PassNTLMv2 value, not PassNT or PassLM### Kerberos / Negotiate Authentication
Some proxies use Negotiate, which can use either Kerberos or NTLM:
git config --global http.proxyauthmethod negotiate
# Works best when:
# - You are on a domain-joined Windows machine
# - Kerberos tickets are valid (check with: klist)### Corporate Proxy PAC Files
Many corporations use PAC (Proxy Auto-Configuration) files:
# Windows: Internet Options > Connections > LAN Settings
# Px can parse PAC files automatically:
px --pac=http://proxy.company.com/proxy.pac### TLS Trust on MITM-Decrypting Proxies
If the proxy decrypts HTTPS and re-signs it with an internal CA, the right fix is to trust that CA, not to disable verification:
# Trust the corporate CA explicitly
git config --global http.sslCAInfo /path/to/corp-ca.pem
# Or, on Windows, use the OS cert store (schannel) where IT deploys the CA
git config --global http.sslBackend schannelNever use http.sslVerify false against a MITM proxy: it disables certificate validation entirely and exposes your credentials and code to interception.
### Security Considerations
1. Never store plaintext passwords in Git config or environment variables. Use CNTLM (hashed) or Px (SSPI), or a secure credential helper.
2. Restrict access to any credential/config files:
chmod 600 ~/.cntlm.conf
chmod 600 ~/.git-credentials3. Bind local proxies to localhost only:
# CNTLM
Listen 127.0.0.1:3128
# NOT: Listen 0.0.0.0:3128### SSH over Port 443 as an Alternative
If NTLM proxy issues persist, SSH over port 443 often bypasses corporate HTTP proxies:
# ~/.ssh/config
Host github.com
HostName ssh.github.com
Port 443
User git
# Switch the remote to SSH
git remote set-url origin [email protected]:user/repo.git### Troubleshooting CNTLM
cntlm -f -c /etc/cntlm.conf -v
# Common issues:
# - 'Credentials rejected' - wrong password hash
# - 'Connection refused' - wrong proxy address
# - 'Timeout' - firewall blocking the connection
# Regenerate the hash after a password change
cntlm -H -d DOMAIN -u username### Git for Windows SSL Backend
# Windows native SSL - uses the OS certificate store, better NTLM and
# corporate-CA interoperability
git config --global http.sslBackend schannel
# Or OpenSSL (pair with http.sslCAInfo for the corporate CA)
git config --global http.sslBackend opensslSchannel often works better with corporate proxies because it uses the Windows native certificate store and authentication.
ssh: Could not resolve hostname github.com: Name or service not known
How to fix 'ssh: Could not resolve hostname github.com: Name or service not known' in Git
error: insufficient permission for adding an object to repository database .git/objects
How to fix "insufficient permission for adding an object to repository database" in Git
fatal: could not create work tree dir 'repo': Permission denied
How to fix "could not create work tree dir: Permission denied" in Git
Smudge error: Error downloading object: The requested URL returned error
How to fix Git LFS 'Smudge error: Error downloading object' error
fetch-pack: unexpected disconnect while reading sideband packet
How to fix 'unexpected disconnect while reading sideband packet' in Git