{"record":{"id":"c0fd4b79a917e00c","repo":"nats-io/nats-server","slug":"invalid-null-character-in-s-q","errorCode":null,"errorMessage":"invalid null character in %s %q","messagePattern":"invalid null character in (.+?) %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":4332,"sourceCode":"\tpp.sz = payloadSize\n\tif pp.sz > 0 {\n\t\tstart = r.pos\n\t\tr.pos += pp.sz\n\t\tpp.msg = r.buf[start:r.pos]\n\t} else if pp.sz == 0 {\n\t\tpp.msg = nil\n\t} else {\n\t\treturn errMQTTInvalidPublishLength\n\t}\n\treturn nil\n}\n\nfunc mqttValidateTopic(topic []byte, field string) error {\n\tif !utf8.Valid(topic) {\n\t\treturn fmt.Errorf(\"invalid utf8 for %s %q\", field, topic)\n\t}\n\tif bytes.IndexByte(topic, 0) >= 0 {\n\t\treturn fmt.Errorf(\"invalid null character in %s %q\", field, topic)\n\t}\n\treturn nil\n}\n\nfunc mqttValidateString(value string, field string) error {\n\tif !utf8.ValidString(value) {\n\t\treturn fmt.Errorf(\"invalid utf8 for %s %q\", field, value)\n\t}\n\tif strings.IndexByte(value, 0) >= 0 {\n\t\treturn fmt.Errorf(\"invalid null character in %s %q\", field, value)\n\t}\n\treturn nil\n}\n\nfunc mqttPubTrace(pp *mqttPublish) string {\n\tdup := pp.flags&mqttPubFlagDup != 0\n\tqos := mqttGetQoS(pp.flags)\n\tretain := mqttIsRetained(pp.flags)","sourceCodeStart":4314,"sourceCodeEnd":4350,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L4314-L4350","documentation":"MQTT forbids the NUL character (U+0000) inside topics ([MQTT-4.7.3-2]); the server rejects any topic containing a 0x00 byte even if the bytes are otherwise valid UTF-8. This prevents ambiguous or injection-prone topic names in the subject tree.","triggerScenarios":"A client sends a SUBSCRIBE/PUBLISH/UNSUBSCRIBE whose topic contains an embedded 0x00 byte, typically from concatenating C strings, zero-padded buffers, or binary data into the topic.","commonSituations":"Buffer-based topic construction where leftover zero bytes are included in the length, embedding binary keys/hashes in topics, or templated topics joined with NUL separators by mistake.","solutions":["Trim or reject NUL bytes from topic strings in the client before publishing/subscribing","Replace binary data in topics with hex/base64 textual encoding","Verify the buffer-length calculation doesn't include padding zeros beyond the string","Escape/strip control characters from user input used to compose topics"],"exampleFix":"// before\ntopic := fmt.Sprintf(\"devices/%s/events\", rawBuf[:cap])\n// after\nt := strings.TrimRight(string(rawBuf[:n]), \"\\x00\")\nif strings.ContainsRune(t, 0) { return errors.New(\"topic contains NUL\") }\ntopic := fmt.Sprintf(\"devices/%s/events\", t)","handlingStrategy":"validation","validationCode":"func topicSafe(t string) bool { return !strings.ContainsRune(t, 0) && utf8.ValidString(t) && len(t) > 0 }","typeGuard":"func hasNoNul(b []byte) bool { return bytes.IndexByte(b, 0) < 0 }","tryCatchPattern":"if err := subscribe(topic); err != nil && strings.Contains(err.Error(), \"null character\") { topic = strings.ReplaceAll(topic, \"\\x00\", \"\"); retry() }","preventionTips":["Trim C-string terminators and buffer padding before using strings as topics","Encode binary identifiers as hex/base64 instead of raw bytes","Use length-aware copies, never whole fixed-size buffers","Add NUL checks in any topic-building utility function"],"tags":["mqtt","topic-validation","null-byte","protocol-violation"],"backgroundTag":"mqtt-protocol-violation","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}