{"record":{"id":"a61ad80f1aeebc93","repo":"jdx/mise","slug":"user-service-the-command-contains-c-whi","errorCode":null,"errorMessage":"user service '{}': the command contains {c:?}, which cmd.exe would reinterpret when `environment` is set; move it into a script","messagePattern":"user service '(.+?)': the command contains (.+?), which cmd\\.exe would reinterpret when `environment` is set; move it into a script","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/scheduled_tasks.rs","lineNumber":229,"sourceCode":"        }\n        if let Some(c) = value\n            .chars()\n            .find(|c| matches!(c, '\"' | '%' | '&' | '|' | '<' | '>' | '^' | '\\n' | '\\r'))\n        {\n            bail!(\n                \"user service '{}': environment value for {key} contains {c:?}, which cmd.exe would reinterpret; set it inside the program instead\",\n                request.name\n            );\n        }\n        sets.push(format!(\"set \\\"{key}={value}\\\"\"));\n    }\n    // the command line goes through cmd.exe too: what it would split or\n    // chain is rejected the same way, rather than run differently\n    if let Some(c) = format!(\"{program} {args}\")\n        .chars()\n        .find(|c| matches!(c, '%' | '&' | '|' | '<' | '>' | '^' | '\\n' | '\\r'))\n    {\n        bail!(\n            \"user service '{}': the command contains {c:?}, which cmd.exe would reinterpret when `environment` is set; move it into a script\",\n            request.name\n        );\n    }\n    let program = if program.contains(char::is_whitespace) {\n        format!(\"\\\"{program}\\\"\")\n    } else {\n        program\n    };\n    let rest = if args.is_empty() {\n        program\n    } else {\n        format!(\"{program} {args}\")\n    };\n    Ok((\n        \"cmd.exe\".to_string(),\n        format!(\"/c {} && {rest}\", sets.join(\" && \")),\n    ))","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/scheduled_tasks.rs#L211-L247","documentation":"When a user service defines environment variables, the whole command line (program + args) is executed through cmd.exe, so characters that cmd treats specially — %, &, |, <, >, ^, and line breaks — would change the meaning of the command. exec_action rejects such command lines up front instead of letting cmd.exe reinterpret them.","triggerScenarios":"Calling render_xml (via exec_action) for a user service that sets request.environment and whose formatted \"{program} {args}\" string contains '%', '&', '|', '<', '>', '^', '\\n', or '\\r'. Note this check only runs when environment is set; without env vars the command bypasses cmd.exe.","commonSituations":"Redirects or pipes written directly into the service command ('app.exe > log.txt'); args containing '&' (URLs, background syntax); '%APPDATA%' style expansion expected in the command; multi-line commands pasted from scripts.","solutions":["Move the redirection/piping/expansion into a wrapper script (.cmd/.ps1) and point the service at that script.","Remove cmd-specific metacharacters from program/args; perform redirects inside the program (e.g. built-in logging).","If env vars are not actually needed, unset request.environment so the command no longer runs through cmd.exe.","Replace '%' expansions with explicit absolute paths."],"exampleFix":"// before\nrequest.environment.insert(\"MODE\".into(), \"prod\".into());\nrequest.args = [\"/c\", \"app.exe > out.log\"].into();\n// after\nrequest.program = \"C:\\\\svc\\\\run.cmd\".into(); // script contains the redirect\nrequest.args = [].into();","handlingStrategy":"validation","validationCode":"fn cmd_safe_command(program: &str, args: &[String]) -> Result<(), String> {\n    let line = format!(\"{program} {}\", args.join(\" \"));\n    if let Some(c) = line.chars().find(|c| matches!(c, '%' | '&' | '|' | '<' | '>' | '^' | '\\n' | '\\r')) {\n        return Err(format!(\"command contains cmd.exe metachar {c:?}; use a wrapper script\"));\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never put redirects, pipes, or %VAR% expansion directly in service commands; wrap in a .cmd/.ps1 script","Only set request.environment when you actually need it — without env vars the command avoids cmd.exe","Use absolute paths without spaces or quote paths containing whitespace","Validate commands at service-definition load time"],"tags":["windows","cmd","injection"],"backgroundTag":"invalid-argument-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}