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 += 4

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Treat the target as untrusted/non-conformant and skip or flag it in scan output
  2. Retry once to rule out transient truncation
  3. Capture raw reply bytes to confirm whether the server is genuinely malformed
  4. 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

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.