projectdiscovery/nuclei · warning
invalid string offset
Error message
invalid string offset
What it means
Thrown by readNullTerminatedASCIIString when its start offset is negative or beyond the end of the buffer. In the MySQL fingerprint flow it is called with start=5 (right after the 4-byte packet header), so this fires when the received handshake packet payload is shorter than 6 bytes — the greeting is too truncated to even contain a version string. It propagates out of IsMySQL / FingerprintMySQL / Connect / ExecuteQuery.
Source
Thrown at pkg/js/libs/mysql/fingerprint.go:361
if caps&clientPluginAuth != 0 && pos < len(payload) {
if plugin, _, err := readNullTerminatedASCIIString(payload, pos); err == nil {
info.AuthPluginName = plugin
}
}
}
func mysqlPacketLength(packet []byte) int {
if len(packet) < 3 {
return 0
}
return int(uint32(packet[0]) | uint32(packet[1])<<8 | uint32(packet[2])<<16)
}
// 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 []byteView on GitHub (pinned to 265b3a3dec)
Solutions
- Verify the port actually speaks MySQL server-first protocol (MySQL sends the greeting before the client sends anything)
- Retry against the canonical MySQL port 3306 to rule out port confusion
- If the target needs a client hello first (or is TLS-wrapped), this library cannot fingerprint it — use the code protocol with a raw net connection instead
- Increase network timeouts / check for packet-dropping middleboxes if the target is a known MySQL server
Defensive patterns
Strategy: try-catch
Validate before calling
// confirm the service sends at least a header + version byte before probing
const conn = net.Open('tcp', host + ':' + port);const b = conn.Recv(16);
conn.Close();
if (!b || b.length < 6) { log('no greeting, skip mysql probe'); } Type guard
function hasMinimumGreeting(b) {
return typeof b === 'string' && b.length >= 6;
} Try / catch
try {
mysql.IsMySQL(host, port);
} catch (e) {
if (String(e).includes('invalid string offset')) { /* truncated greeting: not usable, skip */ }
else { throw e; }
} Prevention
- Probe only ports known/likely to be MySQL server-first services
- Handle truncated-greeting errors as skip, not retry storms
- For TLS-wrapped MySQL, probe over TLS instead of plaintext
- Raise scan timeouts if targets are known-slow and truncation is suspected
When it happens
Trigger: The remote service accepts the TCP connection but sends fewer than 6 payload bytes before closing or before the fingerprint read timeout expires; or sends nothing and the reader times out with a partial/empty buffer. Typical with wrappers, honeypots, or services that immediately close on unknown clients.
Common situations: Probing firewalled ports that accept connections then drop; services that expect a client hello first (so they send no greeting) and time out; network middleboxes truncating responses; very slow servers where the fingerprint timeout hits mid-banner.
Related errors
- unterminated mysql string
- 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/169f7f193ccfdaa1.
Report an issue: GitHub.