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 []byte

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Verify the port actually speaks MySQL server-first protocol (MySQL sends the greeting before the client sends anything)
  2. Retry against the canonical MySQL port 3306 to rule out port confusion
  3. 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
  4. 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

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


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