Back to skill

Security audit

autodl-train

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent remote training helper, but its SSH scripts can exceed the promised project-folder boundary in some configurations, so it needs review before install.

Install only after reviewing the scripts and using a dedicated non-root SSH account limited to the training project. Keep log_path and log_candidates relative to the project, set a non-empty process_match or train_command, prefer key-based SSH over password mode, and avoid using this against servers that contain unrelated sensitive workloads.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/common.py:281
Finding

Base64-Encoded Remote Shell Execution Obscures the Effective Payload

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/common.py:339
Finding

Absolute Log Paths Bypass the Declared Project-Directory Boundary

Content
View full analysis
str: if path_value.startswith("/"): return path_value return posixpath.normpath(posixpath.join(config["project_path"], path_value)) ``` The log reader subsequently reads the supplied path after only changing into the project directory: ```python def read_remote_file_tail(config: Dict[str, Any], path_value: str, *, tail_lines: int) -> Dict[str, Any]: script = f""" {build_guard_block(config)} LOG_PATH={shell_quote(path_value)} if [ ! -f "$LOG_PATH" ]; then echo "LOG_NOT_FOUND=$LOG_PATH" exit 4 fi printf 'LOG_PATH=%s\n' "$LOG_PATH" printf 'LOG_MTIME=%s\n' "$(stat -c '%y' "$LOG_PATH" 2>/dev/null || true)" printf 'LOG_SIZE=%s\n' "$(stat -c '%s' "$LOG_PATH" 2>/dev/null || echo 0)" echo '__LOG_START__' tail -n {int(tail_lines)} "$LOG_PATH" || true echo '__LOG_END__' """.strip() ``` The training launcher also accepts the resolved log path and appends data to it: ```python TRAIN_LOG={shell_quote(log_path)} TRAIN_COMMAND={shell_quote(train_command)} PROCESS_MATCH={shell_quote(process_match)} LAUNCHER_PATH={shell_quote(launcher_path)} mkdir -p "$(dirname "$TRAIN_LOG")" PRE_START_LOG_SIZE=$(stat -c '%s' "$TRAIN_LOG" 2>/dev/null || echo 0) printf '=== AutoDL train operator start ===\n' >> "$TRAIN_LOG" printf 'timestamp=%s\n' "$(date '+%F %T %z')" >> "$TRAIN_LOG" printf 'project=%s\n' "$PROJECT_PATH" >> "$TRAIN_LOG" printf 'command=%s\n' "$TRAIN_COMMAND" >> "$TRAIN_LOG" ``` ### Technical Analysis The Skill states that it operates only inside the configured `project_path`. Although `validate_required_config()` validat ...[truncated 1963 chars]
Remediation
View remediation
&2 exit 2 ;; esac ``` 5. Validate every configured log candidate before using `stat`, `tail`, redirection, or `mkdir`. 6. Use a dedicated unprivileged remote account whose filesystem permissions are limited to the intended project. 7. Add tests covering absolute paths, `..` traversal, symlinks escaping the project, and similarly prefixed directories. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/common.py:406
Finding

Empty Process Matcher Causes Remote Process Enumeration

Content
View full analysis
str: explicit = (config.get("process_match") or "").strip() if explicit: return explicit command = str(config.get("train_command") or "").strip() return " ".join(command.split()[:6]) ``` The empty value is then passed to fixed-string `grep`: ```python def build_status_probe_script(config: Dict[str, Any]) -> str: process_match = build_process_match(config) return f""" {build_guard_block(config)} PROCESS_MATCH={shell_quote(process_match)} printf 'TIME=%s\n' "$(date '+%F %T %z')" printf 'PROCESS_MATCH=%s\n' "$PROCESS_MATCH" echo '__PROCESS_START__' ps -eo pid=,lstart=,etimes=,command= | grep -F -- "$PROCESS_MATCH" | grep -v 'grep -F' || true echo '__PROCESS_END__' echo '__GPU_START__' if command -v nvidia-smi >/dev/null 2>&1; then nvidia-smi --query-compute-apps=pid,process_name,used_gpu_memory --format=csv,noheader,nounits 2>/dev/null || true fi echo '__GPU_END__' """.strip() ``` Status validation does not require a training command: ```python config = load_config(args) validate_required_config(config, require_train_command=False) probe_result = run_remote_script(config, build_status_probe_script(config)) ``` ### Technical Analysis `grep -F -- ""` matches every input line. Therefore, when both process-matching fields are absent or empty, the status probe returns every process visible to the SSH user instead of only the configured training process. This condition is reachable because `check_status.py` calls configuration validation with `require_train_command=False`, and there is no separate require ...[truncated 1189 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (21)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · .gitignore (reported line 1)May include surrounding context.

text
.env
.env.local
config.local.json
config.*.local.json

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · .gitignore (reported line 2)May include surrounding context.

text
.env
.env.local
config.local.json
config.*.local.json
config.private.json

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · config.example.json (reported line 5)May include surrounding context.

json
"host": "YOUR_AUTODL_HOST",
  "port": 22,
  "username": "root",
  "ssh_key_path": "~/.ssh/id_rsa",
  "strict_host_key_checking": "accept-new",
  "project_path": "/root/autodl-tmp/your-project",
  "allowed_project_roots": [

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/troubleshooting.md (reported line 15)May include surrounding context.

md
"host": "YOUR_AUTODL_HOST",
  "port": 22,
  "username": "root",
  "ssh_key_path": "~/.ssh/id_rsa",
  "strict_host_key_checking": "accept-new",
  "project_path": "/root/autodl-tmp/your-project",
  "allowed_project_roots": [

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/usage.md (reported line 24)May include surrounding context.

md
"host": "region-1.autodl.example",
  "port": 22,
  "username": "root",
  "ssh_key_path": "~/.ssh/id_ed25519",
  "project_path": "/root/autodl-tmp/your-project",
  "allowed_project_roots": ["/root/autodl-tmp"],
  "env_name": "llm-train",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/common.py (reported line 86)May include surrounding context.

python
def __init__(self, description: str) -> None:
        super().__init__(description=description)
        self.add_argument("--config", help="Path to a JSON config file.")
        self.add_argument("--env-file", help="Path to a .env file.")
        self.add_argument("--host")
        self.add_argument("--port", type=int)
        self.add_argument("--username")

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/common.py (reported line 165)May include surrounding context.

python
file_data = json.load(handle)
        config.update(file_data)

    env_data = os.environ.copy()
    env_data.update(load_env_file(getattr(args, "env_file", None)))
    for key, env_name in ENV_MAP.items():
        value = env_data.get(env_name)

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/common.py (reported line 310)May include surrounding context.

python
file_data = json.load(handle)
        config.update(file_data)

    env_data = os.environ.copy()
    env_data.update(load_env_file(getattr(args, "env_file", None)))
    for key, env_name in ENV_MAP.items():
        value = env_data.get(env_name)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill explicitly instructs the agent to read files, access environment-provided secrets, and execute shell commands over SSH, but it does not declare any tool scope such as permissions or allowed-tools. That creates a capability/visibility mismatch: a reviewer or enforcement layer cannot easily constrain or audit what the skill is allowed to access, increasing the risk of unintended command execution, secret exposure, or broader filesystem interaction than expected.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/troubleshooting.md (reported line 15)May include surrounding context.

md
- Confirm `host`, `port`, `username`, and `ssh_key_path`.
- Test SSH manually with the same host and key.
- Ensure the key has correct permissions such as `chmod 600 ~/.ssh/id_rsa`.
- If host key prompts block automation, keep `strict_host_key_checking` as `accept-new` or pre-populate `known_hosts`.
- If the server is password-based, export `AUTOCLAW_TRAIN_SSH_PASSWORD` before running the scripts.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code handles an SSH password by placing it into an environment variable and creating an askpass helper script, which increases exposure of a sensitive credential to local process inspection, crash dumps, inherited environments, or accidental logging. In a skill explicitly designed to operate remote servers, this is more dangerous because compromise of the credential grants direct infrastructure access.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/common.py (reported line 320)May include surrounding context.

python
env.setdefault("DISPLAY", "autoclaw:0")

    try:
        result = subprocess.run(
            command,
            input=None if ssh_password else script,
            text=True,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This Python file contains multiple natural-language strings presented to users in Chinese, such as failure causes and remediation guidance. The skill does not indicate that it is intentionally region-specific or provide any user opt-in for language selection, which conflicts with the language/locale policy criterion.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The convergence assessment strings returned by the code are all in Chinese, and they flow directly into the final human-readable summary. Because no alternative language path or opt-in is provided, the skill enforces a specific locale in user-visible output.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The assembled human_summary is entirely composed of Chinese phrases, which means end users receive output in a fixed language regardless of preference. This is a natural-language policy issue because the file does not offer opt-in, negotiation, or justification for the locale restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The assessment strings returned to the user are hard-coded in Chinese, including the default summary and bottleneck warnings. This forces a specific language for user-facing output without opt-in or justification, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/remote_train.py (reported line 58)May include surrounding context.

python
{build_activation_block(config)}
exec {train_command}
EOF_AUTOCLAW_LAUNCHER
chmod 700 "$LAUNCHER_PATH"
nohup "$LAUNCHER_PATH" >> "$TRAIN_LOG" 2>&1 < /dev/null &
PID=$!
sleep 2

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/remote_train.py (reported line 59)May include surrounding context.

python
exec {train_command}
EOF_AUTOCLAW_LAUNCHER
chmod 700 "$LAUNCHER_PATH"
nohup "$LAUNCHER_PATH" >> "$TRAIN_LOG" 2>&1 < /dev/null &
PID=$!
sleep 2
RUNNING=0

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The short description forces a specific language in user-facing metadata and does not offer any language/locale choice or explain that the skill is intended only for Chinese-speaking users. This can violate language/locale policy when skills are expected to avoid imposing a language without user opt-in.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

This is a manifest/config file, so vague-trigger checks apply. The file defines operational parameters for SSH access and training execution, but provides no activation constraints, invocation scope, or exclusion conditions that would clarify when this skill should or should not be used.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The example configuration hard-codes SSH access as the root user, normalizing privileged remote operation as the default path. In the context of a skill that executes training operations over SSH, this increases the blast radius of any command misuse, path manipulation, or downstream compromise on the remote host.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.