{"record":{"id":"8ed78cf8e0b6485e","repo":"projectdiscovery/nuclei","slug":"ntlm-base64-decode-w","errorCode":null,"errorMessage":"ntlm: base64 decode: %w","messagePattern":"ntlm: base64 decode: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/js/libs/http/ntlm.go","lineNumber":82,"sourceCode":"\nfunc decodeNTLMBlob(blob string) ([]byte, error) {\n\ts := strings.TrimSpace(blob)\n\tif s == \"\" {\n\t\treturn nil, fmt.Errorf(\"ntlm: empty blob\")\n\t}\n\tlower := strings.ToLower(s)\n\tswitch {\n\tcase strings.HasPrefix(lower, \"ntlm \"):\n\t\ts = strings.TrimSpace(s[5:])\n\tcase strings.HasPrefix(lower, \"negotiate \"):\n\t\ts = strings.TrimSpace(s[10:])\n\t}\n\t// Some servers return \"Negotiate <spnego>\" - still try base64 of remainder.\n\traw, err := base64.StdEncoding.DecodeString(s)\n\tif err != nil {\n\t\traw, err = base64.RawStdEncoding.DecodeString(s)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"ntlm: base64 decode: %w\", err)\n\t\t}\n\t}\n\treturn raw, nil\n}\n\nfunc parseNTLMMessage(data []byte) (*NTLMInfo, error) {\n\tif len(data) < 12 {\n\t\treturn nil, fmt.Errorf(\"ntlm: message too short\")\n\t}\n\tif !bytes.HasPrefix(data, []byte(\"NTLMSSP\\x00\")) {\n\t\treturn nil, fmt.Errorf(\"ntlm: missing NTLMSSP signature\")\n\t}\n\tmsgType := binary.LittleEndian.Uint32(data[8:12])\n\tinfo := &NTLMInfo{MessageType: int(msgType)}\n\tif msgType != 2 {\n\t\t// Type 1/3: return type only; TargetInfo is Type-2 specific.\n\t\treturn info, nil\n\t}","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/http/ntlm.go#L64-L100","documentation":"Thrown by http.DecodeNTLM in nuclei's JavaScript HTTP library when the input cannot be base64-decoded. The helper strips an optional 'NTLM ' or 'Negotiate ' prefix, then tries base64.StdEncoding followed by base64.RawStdEncoding; when both fail it wraps the underlying Go base64 error. It means the value passed in was not an NTLM SSP token at all.","triggerScenarios":"Calling http.DecodeNTLM() with: the bare scheme 'NTLM' (no token after the prefix), a 'Negotiate' header whose token is URL-safe base64 or a Kerberos SPNEGO token, a comma-joined multi-scheme header such as 'Negotiate, NTLM TlRMTVNT...', arbitrary non-base64 text, or base64 containing embedded whitespace or folded newlines.","commonSituations":"Templates that read WWW-Authenticate from servers preferring Kerberos over NTLM; passing the whole response object instead of the header string; servers that advertise several auth schemes in one header; tokens copied truncated out of Burp or docs.","solutions":["Split multi-scheme headers on ',' and pass only the single token that follows the 'NTLM ' (or 'Negotiate ') prefix","Verify the remainder after prefix removal matches /^[A-Za-z0-9+/]+={0,2}$/ before calling DecodeNTLM","Strip whitespace and line-fold characters from long base64 tokens before decoding","If the blob is a Kerberos SPNEGO token, do not use DecodeNTLM at all; it only parses NTLMSSP"],"exampleFix":"// before\nconst info = http.DecodeNTLM(resp.GetHeader('WWW-Authenticate'));\n\n// after\nconst header = resp.GetHeader('WWW-Authenticate') || '';\nconst part = header.split(',').map(h => h.trim()).find(h => /^(ntlm|negotiate)\\s+\\S+/i.test(h));\nif (part) {\n  const info = http.DecodeNTLM(part);\n}","handlingStrategy":"validation","validationCode":"function extractNTLMToken(header) {\n  if (!header) return null;\n  const part = header.split(',').map(h => h.trim()).find(h => /^(ntlm|negotiate)\\s+\\S+/i.test(h));\n  if (!part) return null;\n  const token = part.replace(/^(ntlm|negotiate)\\s+/i, '');\n  return /^[A-Za-z0-9+/]+={0,2}$/.test(token) ? token : null;\n}\nconst token = extractNTLMToken(resp.GetHeader('WWW-Authenticate'));\nif (token) {\n  const info = http.DecodeNTLM(token);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const info = http.DecodeNTLM(token);\n} catch (e) {\n  // Header was not an NTLMSSP blob; treat endpoint as non-NTLM and skip NTLM assertions\n}","preventionTips":["Never pass a raw multi-scheme WWW-Authenticate value; select the NTLM token first","Send a Type-1 negotiate with http.NegotiateNTLM() and decode only the second response, which is guaranteed NTLMSSP","Check the header exists and carries a payload after the scheme name before decoding"],"tags":["ntlm","http","base64","header-parsing"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}