shadow1ng/fscan · error
invalid SCRAM salt: %w
Error message
invalid SCRAM salt: %w
What it means
Guard in buildMongoSCRAMClientFinal: the base64-decoded SCRAM salt from the MongoDB server-first message could not be used (decode failure or unusable length). The SCRAM-SHA-1 exchange cannot continue because ClientKey computation requires the salt and iteration count.
Source
Thrown at plugins/services/mongodb.go:515
}
return reply, nil
}
func buildMongoSCRAMClientFinal(username, password, clientFirstBare, serverFirst string) (string, error) {
attrs := parseSCRAMAttributes(serverFirst)
serverNonce := attrs["r"]
saltB64 := attrs["s"]
iterText := attrs["i"]
if serverNonce == "" || saltB64 == "" || iterText == "" {
return "", fmt.Errorf("invalid SCRAM server-first payload")
}
clientNonce := scramAttr(clientFirstBare, "r")
if clientNonce == "" || !strings.HasPrefix(serverNonce, clientNonce) {
return "", fmt.Errorf("invalid SCRAM nonce")
}
salt, err := base64.StdEncoding.DecodeString(saltB64)
if err != nil {
return "", fmt.Errorf("invalid SCRAM salt: %w", err)
}
iterations, err := strconv.Atoi(iterText)
if err != nil || iterations <= 0 {
return "", fmt.Errorf("invalid SCRAM iteration count")
}
clientFinalWithoutProof := "c=biws,r=" + serverNonce
authMessage := clientFirstBare + "," + serverFirst + "," + clientFinalWithoutProof
digest := md5.Sum([]byte(username + ":mongo:" + password))
saltedPassword := pbkdf2.Key([]byte(fmt.Sprintf("%x", digest)), salt, iterations, sha1.Size, sha1.New)
clientKey := mongoHMAC(saltedPassword, []byte("Client Key"))
storedKey := sha1.Sum(clientKey)
clientSignature := mongoHMAC(storedKey[:], []byte(authMessage))
proof := make([]byte, len(clientKey))
for i := range clientKey {
proof[i] = clientKey[i] ^ clientSignature[i]
}
return clientFinalWithoutProof + ",p=" + base64.StdEncoding.EncodeToString(proof), nilView on GitHub (pinned to 95cc12e753)
Solutions
- Inspect the s= value for non-standard base64 characters or bad padding
- Support RawStdEncoding/URL-safe fallback decoding if a non-standard server is expected
- Capture the raw reply to check for truncation en route
- Confirm against a known-good mongod that the payload decodes cleanly
Example fix
// before
salt, err := base64.StdEncoding.DecodeString(saltB64)
// after
salt, err := base64.StdEncoding.DecodeString(saltB64)
if err != nil {
salt, err = base64.RawStdEncoding.DecodeString(strings.TrimRight(saltB64, "="))
} Defensive patterns
Strategy: validation
Validate before calling
if _, err := base64.StdEncoding.DecodeString(saltB64); err != nil {
return fmt.Errorf("salt not standard base64: %w", err)
} Type guard
func isValidB64(s string) bool {
_, err := base64.StdEncoding.DecodeString(s)
return err == nil && len(s) > 0
} Try / catch
final, err := buildMongoSCRAMClientFinal(u, p, cfb, serverFirst)
if err != nil {
var b64Err base64.CorruptInputError
if errors.As(err, &b64Err) {
log.Warnf("salt base64 corrupt at offset %d", int(b64Err))
return
}
return err
} Prevention
- Check the s= attribute alphabet before decoding
- Capture raw replies when scanning through proxies
- Only expect standard base64 salts from stock mongod
When it happens
Trigger: The s= attribute in the server-first payload contains characters outside the standard base64 alphabet or has wrong padding — e.g. URL-safe base64 (-/ instead of +/), whitespace, or truncation by a middlebox.
Common situations: Proxies rewriting payloads; custom server implementations that URL-safe-encode the salt; corrupted scan traffic over unreliable links.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- invalid SCRAM server-first payload
- invalid SCRAM iteration count
- authentication failed: %s
- invalid saslStart response
- invalid SCRAM nonce
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/5e6a8b30588f1ea2.
Report an issue: GitHub.