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
- If the target is a known MySQL server, retry when the network is less loaded and check for MTU/firewall truncation
- Confirm the port serves MySQL (server-first greeting, version NUL-terminated)
- Treat as 'not MySQL' in template logic — this is a probe failure, not a scanner defect
- 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
- Expect truncated banners on slow links; treat as skip
- Avoid pointing the mysql lib at streaming/text services
- Reuse one raw pre-read to validate greeting shape before all mysql calls
- Retry manually with longer timeouts only for known-good MySQL targets
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
- invalid string offset
- mysql handshake packet too short
- mysql handshake filler byte is not zero
- truncated PL option token
- empty mysql greeting
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/c6ca2d4b6ee0e36d.
Report an issue: GitHub.