{"record":{"id":"000718a88e51d6a0","repo":"projectdiscovery/nuclei","slug":"encountered-invalid-ascii-character","errorCode":null,"errorMessage":"encountered invalid ASCII character","messagePattern":"encountered invalid ASCII character","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/js/libs/mysql/fingerprint.go","lineNumber":373,"sourceCode":"}\n\n// readNullTerminatedASCIIString mirrors fingerprintx: printable ASCII only,\n// returns the index of the NUL terminator (not the next byte).\nfunc readNullTerminatedASCIIString(buf []byte, start int) (string, int, error) {\n\tif start < 0 || start >= len(buf) {\n\t\treturn \"\", 0, fmt.Errorf(\"invalid string offset\")\n\t}\n\tvar characters []byte\n\tfor position := start; position < len(buf); position++ {\n\t\tc := buf[position]\n\t\tif c >= 0x20 && c <= 0x7e {\n\t\t\tcharacters = append(characters, c)\n\t\t\tcontinue\n\t\t}\n\t\tif c == 0x00 {\n\t\t\treturn string(characters), position, nil\n\t\t}\n\t\treturn \"\", 0, fmt.Errorf(\"encountered invalid ASCII character\")\n\t}\n\treturn \"\", 0, fmt.Errorf(\"unterminated mysql string\")\n}\n\nfunc readPrintableASCII(buf []byte) string {\n\tvar characters []byte\n\tfor _, c := range buf {\n\t\tif c >= 0x20 && c <= 0x7e {\n\t\t\tcharacters = append(characters, c)\n\t\t}\n\t}\n\treturn string(characters)\n}\n\nfunc bytesTrimRightNull(b []byte) []byte {\n\tfor len(b) > 0 && b[len(b)-1] == 0x00 {\n\t\tb = b[:len(b)-1]\n\t}","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/mysql/fingerprint.go#L355-L391","documentation":"Thrown by readNullTerminatedASCIIString when it hits a byte that is neither printable ASCII (0x20-0x7e) nor the NUL terminator while scanning the server version string of a MySQL handshake packet. The MySQL version field must be human-readable ASCII terminated by 0x00, so binary garbage means the payload is not a MySQL greeting. It propagates out of IsMySQL / FingerprintMySQL / Connect / ExecuteQuery.","triggerScenarios":"The first bytes of the response happen to look like a packet header, but the region at offset 5+ contains binary data: TLS records (probing a TLS-wrapped MySQL port in plaintext), compressed or encrypted banners, or any binary protocol on the target port.","commonSituations":"MySQL with require_secure_transport or behind an SSL terminator — the plaintext probe reads TLS ClientAlert/ServerHello bytes; non-MySQL binary services on scanned ports; protocol-detection templates run broadly across a target's port range.","solutions":["Check whether the MySQL port requires TLS; if so, fingerprint via a TLS connection (e.g. code protocol with net.OpenTLS or SSL protocol) instead of the plaintext MySQL probe","Confirm the port number — this usually means a non-MySQL binary service answered","Treat the error as 'not MySQL (plaintext)' and continue the scan","Capture the raw response with a raw socket to identify what actually answered"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// reject binary/TLS-looking banners before the mysql probe\nconst conn = net.Open('tcp', host + ':' + port);\nconst b = conn.Recv(16);\nconn.Close();\n// TLS records start 0x16 0x03; MySQL greetings start with a length + 0x0a\nif (b.charCodeAt(0) === 0x16) { log('TLS on port, use TLS probe'); }","typeGuard":"function isPrintableAsciiPrefix(s) {\n  for (let i = 5; i < s.length && s.charCodeAt(i) !== 0; i++) {\n    const c = s.charCodeAt(i);\n    if (c < 0x20 || c > 0x7e) return false;\n  }\n  return true;\n}","tryCatchPattern":"try {\n  mysql.IsMySQL(host, port);\n} catch (e) {\n  if (String(e).includes('invalid ASCII character')) { /* binary banner: not plaintext mysql */ }\n  else { throw e; }\n}","preventionTips":["Check whether the MySQL port enforces TLS before plaintext probing","Filter obviously binary banners with a raw net.Open+Recv pre-read","Treat ASCII parse failures as 'not plaintext MySQL'","Use the code protocol for non-standard or wrapped deployments"],"tags":["mysql","fingerprinting","tls","protocol-parsing"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}