projectdiscovery/nuclei · error
ntlm: challenge too short
Error message
ntlm: challenge too short
What it means
The message was identified as Type-2 (challenge) but is shorter than 48 bytes. A Type-2 message has a 48-byte fixed part (signature, type, target name/offset, negotiate flags, context handle, and target-info length/offset at bytes 40-48); with fewer bytes the targetInfoOffset read at data[44:48] would go out of bounds, so parsing aborts.
Source
Thrown at pkg/js/libs/http/ntlm.go:102
}
return raw, nil
}
func parseNTLMMessage(data []byte) (*NTLMInfo, error) {
if len(data) < 12 {
return nil, fmt.Errorf("ntlm: message too short")
}
if !bytes.HasPrefix(data, []byte("NTLMSSP\x00")) {
return nil, fmt.Errorf("ntlm: missing NTLMSSP signature")
}
msgType := binary.LittleEndian.Uint32(data[8:12])
info := &NTLMInfo{MessageType: int(msgType)}
if msgType != 2 {
// Type 1/3: return type only; TargetInfo is Type-2 specific.
return info, nil
}
if len(data) < 48 {
return nil, fmt.Errorf("ntlm: challenge too short")
}
targetNameLen := binary.LittleEndian.Uint16(data[12:14])
targetNameOffset := binary.LittleEndian.Uint32(data[16:20])
if targetNameLen > 0 && int(targetNameOffset)+int(targetNameLen) <= len(data) {
info.TargetName = decodeUTF16LE(data[targetNameOffset : targetNameOffset+uint32(targetNameLen)])
}
negotiateFlags := binary.LittleEndian.Uint32(data[20:24])
targetInfoLen := binary.LittleEndian.Uint16(data[40:42])
targetInfoOffset := binary.LittleEndian.Uint32(data[44:48])
start := uint64(targetInfoOffset)
end := start + uint64(targetInfoLen)
if targetInfoLen > 0 && end <= uint64(len(data)) {
parseAVPairs(data[int(start):int(end)], info)
}
View on GitHub (pinned to 265b3a3dec)
Solutions
- Re-fetch the challenge directly (bypass any proxy) since the header value may have been clipped in transit
- Treat endpoints that consistently produce short challenges as non-NTLM and skip the decode
- When expecting a challenge, verify the token decodes to at least 48 bytes (64 base64 characters) before parsing
Defensive patterns
Strategy: try-catch
Validate before calling
function isChallengeSized(token) {
// 48-byte Type-2 fixed part needs at least 64 base64 characters
return token.replace(/=+$/, '').length >= 64;
} Try / catch
try {
const info = http.DecodeNTLM(challengeToken);
} catch (e) {
// Malformed/truncated Type-2 challenge; treat endpoint as non-NTLM
} Prevention
- Fetch challenges directly without proxy rewrites when possible
- Validate the token decodes to at least 48 bytes before asserting Type-2 fields
When it happens
Trigger: A truncated challenge token that still decodes to between 12 and 47 bytes; a non-compliant server emitting an abbreviated challenge; middleware rewriting or clipping the WWW-Authenticate value in transit.
Common situations: Reverse proxies or WAFs shortening long header values; embedded devices with quirky SMB/HTTP stacks; templates run against honeypots that emit synthetic NTLM-looking payloads.
Related errors
- ntlm: message too short
- failed to parse NTLM response: %w
- expected NTLM challenge message, got type %d
- no templates provided for scan
- template threads must be at least 1
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/2fa836cb9c46b4bc.
Report an issue: GitHub.