projectdiscovery/nuclei · warning

unterminated mysql string

Error message

unterminated mysql string

What it means

Thrown by readNullTerminatedASCIIString when it scans to the end of the handshake packet without ever finding the 0x00 terminator for the server version string. A valid MySQL greeting always NUL-terminates its version, so an unterminated run of printable bytes means the buffer is truncated or the payload is not a greeting. It propagates out of IsMySQL / FingerprintMySQL / Connect / ExecuteQuery.

Source

Thrown at pkg/js/libs/mysql/fingerprint.go:375

// readNullTerminatedASCIIString mirrors fingerprintx: printable ASCII only,
// returns the index of the NUL terminator (not the next byte).
func readNullTerminatedASCIIString(buf []byte, start int) (string, int, error) {
	if start < 0 || start >= len(buf) {
		return "", 0, fmt.Errorf("invalid string offset")
	}
	var characters []byte
	for position := start; position < len(buf); position++ {
		c := buf[position]
		if c >= 0x20 && c <= 0x7e {
			characters = append(characters, c)
			continue
		}
		if c == 0x00 {
			return string(characters), position, nil
		}
		return "", 0, fmt.Errorf("encountered invalid ASCII character")
	}
	return "", 0, fmt.Errorf("unterminated mysql string")
}

func readPrintableASCII(buf []byte) string {
	var characters []byte
	for _, c := range buf {
		if c >= 0x20 && c <= 0x7e {
			characters = append(characters, c)
		}
	}
	return string(characters)
}

func bytesTrimRightNull(b []byte) []byte {
	for len(b) > 0 && b[len(b)-1] == 0x00 {
		b = b[:len(b)-1]
	}
	return b
}

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. If the target is a known MySQL server, retry when the network is less loaded and check for MTU/firewall truncation
  2. Confirm the port serves MySQL (server-first greeting, version NUL-terminated)
  3. Treat as 'not MySQL' in template logic — this is a probe failure, not a scanner defect
  4. Compare with a manual read: `net.Open('tcp','host:port')` + Recv and inspect whether the version string ends with a 0x00 byte
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the version string is NUL-terminated within the first bytes
const conn = net.Open('tcp', host + ':' + port);
const b = conn.Recv(64);
conn.Close();
if (b.indexOf('\u0000', 5) === -1) { log('no NUL terminator, skip'); }

Type guard

function isNulTerminatedAt(b) {
  return b.indexOf('\u0000', 5) !== -1;
}

Try / catch

try {
  mysql.FingerprintMySQL(host, port);
} catch (e) {
  if (String(e).includes('unterminated mysql string')) { /* truncated/greeting-less: skip */ }
  else { throw e; }
}

Prevention

When it happens

Trigger: The read deadline (mysqlFingerprintTimeout) expires mid-banner leaving a partial packet; the server sends a banner with no NUL inside the received window; or a non-MySQL service streams printable text (e.g. an HTTP banner or SMTP greeting) that never terminates within the buffer.

Common situations: Slow or heavily loaded MySQL servers whose greeting is split across TCP segments with only the first part read; services that keep the connection open and send continuous text; MTU/fragmentation issues or middleboxes clipping packets.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/c6ca2d4b6ee0e36d. Report an issue: GitHub.