Skip to content

[Bug] environment.py _append_env_to_profile shell injection — env value written unescaped to ~/.zshrc / ~/.bashrc #425

Description

@vipul674

Describe the bug

In daemon/pilot/system/environment.py, the _append_env_to_profile function writes environment variable values directly into shell profile files (~/.zshrc, ~/.bashrc) without escaping special characters. A value containing double quotes, backticks, $ signs, or other shell metacharacters will break the shell syntax of the profile file, causing errors on every shell login.

This is a shell injection vulnerability in the persistent environment variable feature. The value is user-controlled (enters through the LLM action pipeline via EnvParams), and when persistent=True, it is written to a sourced shell script.

Steps to reproduce

  1. Set a persistent environment variable where value contains a double quote:
    env_set("MY_VAR", 'hello"world$(id)', persistent=True)
    
  2. The profile file (~/.zshrc or ~/.bashrc) will contain:
    export MY_VAR="hello"world$(id)"  # pilot-env:MY_VAR
  3. Open a new shell. The shell will either error out or execute the injected $(id) command.

Expected behaviour

The value should be properly escaped for shell context:

escaped_value = value.replace('\\', '\\\\').replace('"', '\\"').replace('$', '\\$').replace('`', '\\`')
new_lines.append(f'export {name}="{escaped_value}"  {marker}\n')

Or ideally, use a shell-safe serialization format (e.g., base64-encode the value).

Actual behaviour

Value is written unescaped at daemon/pilot/system/environment.py:67:

new_lines.append(f'export {name}="{value}"  {marker}\n')

Code reference

daemon/pilot/system/environment.py:55-70:

async def _append_env_to_profile(profile_path: str, name: str, value: str) -> None:
    """Append or update an env var in a shell profile file."""
    marker = f"# pilot-env:{name}"

    try:
        with open(profile_path) as f:
            lines = f.readlines()
    except FileNotFoundError:
        lines = []

    # Remove old entry
    new_lines = [l for l in lines if marker not in l]
    new_lines.append(f'export {name}="{value}"  {marker}\n')  # <-- BUG: value not escaped

    with open(profile_path, "w") as f:
        f.writelines(new_lines)

Environment

  • OS: Linux, macOS (both use shell profiles for persistent env vars)
  • Heliox OS version: Current HEAD

GSSoC 2026 -- This issue is assigned to @vipul674 for implementation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions