Summary
landing/app/git_workflow.py:139,147 interpolates a caller-supplied message into a single-quoted bash -c string:
commit_msg = message or "save: work in progress"
... f"git commit -m '{commit_msg}'"
run via exec_in_pod(pod_name, ["bash", "-c", ...]). A message containing a single quote breaks out of the quoting and injects arbitrary shell into the build pod.
Current reachability
Not reachable from the HTTP surface today: build_save (routes/build.py:135) calls wf.save(...) without passing message. But the parameter exists, the endpoint is docstringed "named save," and the moment a save-message field is wired to the UI this becomes RCE-in-pod.
Suggested fix
Don't interpolate untrusted text into a shell string. Pass the commit message as a separate argv element — e.g. build the commit with ["git", "commit", "-m", commit_msg] via a direct exec (no bash -c), or write the message to a file and git commit -F. Same care applies anywhere else a user string reaches bash -c.
Found during a repo audit.
Summary
landing/app/git_workflow.py:139,147interpolates a caller-suppliedmessageinto a single-quotedbash -cstring:run via
exec_in_pod(pod_name, ["bash", "-c", ...]). Amessagecontaining a single quote breaks out of the quoting and injects arbitrary shell into the build pod.Current reachability
Not reachable from the HTTP surface today:
build_save(routes/build.py:135) callswf.save(...)without passingmessage. But the parameter exists, the endpoint is docstringed "named save," and the moment a save-message field is wired to the UI this becomes RCE-in-pod.Suggested fix
Don't interpolate untrusted text into a shell string. Pass the commit message as a separate argv element — e.g. build the commit with
["git", "commit", "-m", commit_msg]via a direct exec (nobash -c), or write the message to a file andgit commit -F. Same care applies anywhere else a user string reachesbash -c.Found during a repo audit.