{"record":{"id":"21637055f7440c20","repo":"multica-ai/multica","slug":"fixed-args-entries-cannot-contain-nul-bytes","errorCode":null,"errorMessage":"fixed_args entries cannot contain NUL bytes","messagePattern":"fixed_args entries cannot contain NUL bytes","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/internal/handler/runtime_profile.go","lineNumber":96,"sourceCode":"// visibility control only once those read paths enforce creator visibility.\n// Follow-up: MUL-3308.\nconst runtimeProfileDefaultVisibility = \"workspace\"\n\n// marshalFixedArgs validates and JSON-encodes the fixed_args list. Each entry\n// must be a non-empty string; the column defaults to an empty array.\nfunc marshalFixedArgs(args []string) ([]byte, error) {\n\tif len(args) == 0 {\n\t\treturn []byte(\"[]\"), nil\n\t}\n\tclean := make([]string, 0, len(args))\n\tfor _, a := range args {\n\t\t// fixed_args are launch flags inherited by every agent on the runtime;\n\t\t// blank entries are always a client mistake.\n\t\tif strings.TrimSpace(a) == \"\" {\n\t\t\treturn nil, errors.New(\"fixed_args entries must be non-empty\")\n\t\t}\n\t\tif strings.ContainsRune(a, '\\x00') {\n\t\t\treturn nil, errors.New(\"fixed_args entries cannot contain NUL bytes\")\n\t\t}\n\t\tclean = append(clean, a)\n\t}\n\treturn json.Marshal(clean)\n}\n\nfunc validateRuntimeProfileCommandName(commandName string) error {\n\tif commandName == \"\" {\n\t\treturn errors.New(\"command_name is required\")\n\t}\n\tif strings.ContainsAny(commandName, \" \\t\\r\\n\") {\n\t\treturn errors.New(\"command_name must be a single executable token; put arguments in fixed_args\")\n\t}\n\tif strings.ContainsRune(commandName, '\\x00') {\n\t\treturn errors.New(\"command_name cannot contain NUL bytes\")\n\t}\n\treturn nil\n}","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/handler/runtime_profile.go#L78-L114","documentation":"marshalFixedArgs rejects fixed_args entries containing the NUL byte (\\x00). Go strings can hold NUL, but OS exec argv is C-string terminated, so a NUL inside an argument would silently truncate the flag at exec time. The check exists to fail fast at the API boundary instead of corrupting the spawned command line.","triggerScenarios":"POST/PUT a runtime profile whose fixed_args contains a literal \\u0000 — usually binary data, a protocol frame, or a string built from a buffer that was not validated as UTF-8 text.","commonSituations":"Reading args from a binary config or message queue into strings; fuzzing tools injecting NUL; encoding mishaps where UCS-4/UTF-32 text is decoded per-byte leaving NULs between characters.","solutions":["Sanitize entries: a.replace(/\\x00/g, \"\") or reject at the client with a clear message","Verify the source of the args is text (decode as UTF-8 and validate) before building the payload","If you actually need to pass a NUL-containing value, that is impossible via argv — redesign to pass a file path or env var"],"exampleFix":"// before\nfixedArgs: buffer.toString(\"utf8\").split(\"\\n\")\n// after\nfixedArgs: buffer.toString(\"utf8\").split(\"\\n\").map(s => s.replace(/\\x00/g, \"\")).filter(Boolean)","handlingStrategy":"validation","validationCode":"const hasNul = (s: string) => s.includes('\\x00');\nconst safeArgs = fixedArgs.map(a => a.replace(/\\x00/g, ''));\nif (fixedArgs.some(hasNul)) log.warn('NUL bytes stripped from fixed_args');","typeGuard":"function isNulFree(s: string): boolean { return !s.includes('\\x00'); }","tryCatchPattern":null,"preventionTips":["Treat NUL in argv-destined strings as producer corruption — investigate the source","Validate config text is valid UTF-8 without NUL at ingestion","NUL cannot be passed through argv at all; redesign around files or env vars"],"tags":["validation","runtime-profile","nul-byte","security"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}