shadow1ng/fscan · error
truncated verifier
Error message
truncated verifier
What it means
After reading the verifier length, getExports checks that verifierLen bytes of verifier data actually fit in the remaining reply. If the declared verifier length exceeds the bytes present, the reply is truncated and cannot be parsed. This protects the parser from out-of-bounds reads on malformed input.
Source
Thrown at plugins/services/nfs.go:150
}
msgType := binary.BigEndian.Uint32(reply[4:8])
if msgType != 1 { // REPLY
return nil, fmt.Errorf("not a reply")
}
replyStatus := binary.BigEndian.Uint32(reply[8:12])
if replyStatus != 0 { // MSG_ACCEPTED
return nil, fmt.Errorf("reply rejected")
}
// Skip auth verifier
offset := 12
if offset+8 > len(reply) {
return nil, fmt.Errorf("truncated")
}
// verifier flavor + length
verifierLen := binary.BigEndian.Uint32(reply[offset+4 : offset+8])
if verifierLen > uint32(len(reply)-offset-8) {
return nil, fmt.Errorf("truncated verifier")
}
offset += 8 + int(verifierLen)
if pad := (4 - verifierLen%4) % 4; pad > 0 {
if int(pad) > len(reply)-offset {
return nil, fmt.Errorf("truncated verifier padding")
}
offset += int(pad)
}
// Accept status
if offset+4 > len(reply) {
return nil, fmt.Errorf("truncated")
}
acceptStatus := binary.BigEndian.Uint32(reply[offset : offset+4])
if acceptStatus != 0 { // SUCCESS
return nil, fmt.Errorf("accept status: %d", acceptStatus)
}
offset += 4View on GitHub (pinned to 95cc12e753)
Solutions
- Treat the target as untrusted/non-conformant and skip or flag it in scan output
- Retry once to rule out transient truncation
- Capture raw reply bytes to confirm whether the server is genuinely malformed
- Keep maxPayload-sized bounds and report the server as failing the mount protocol
Example fix
// before
// server declares verifierLen = 9000 but sends only 20 bytes
// after
// guard the caller: scan continues to next host and records the failure
exports, err := getExports(conn, ...)
if err != nil {
log.Printf("host %s: bad mountd reply: %v", host, err)
return
} Defensive patterns
Strategy: validation
Validate before calling
if len(reply) < 12 { return fmt.Errorf("reply too short to contain a verifier") } Type guard
func verifierFits(reply []byte) bool {
if len(reply) < 16 { return false }
vlen := binary.BigEndian.Uint32(reply[16:20])
return int(vlen) <= len(reply)-20
} Try / catch
if err != nil && strings.Contains(err.Error(), "truncated verifier") {
log.Printf("host sent malformed mountd reply; marking non-conformant")
return nil
} Prevention
- Treat untrusted scan targets as adversarial — never trust declared lengths
- Flag hosts failing bounds checks instead of retrying indefinitely
- Capture raw bytes when a host repeatedly fails to diagnose its stack
When it happens
Trigger: Calling Scan or TestNFSGetExportsHandlesVerifierPadding when a malicious/broken server declares a verifier longer than the data it sent, or the reply was cut off inside the verifier.
Common situations: Fuzzed or hostile target crafting an oversized verifier length; truncated transfer from a buggy middlebox; a non-RPC service returning arbitrary bytes that coincidentally pass earlier checks.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/bd7c2b2115955085.
Report an issue: GitHub.