Back to skill

Security audit

OpenClaw Repo Autopilot

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed unattended repo-automation skill, but it needs Review because it can run broad write-capable AI CLIs, destructively reset/clean repositories, and mishandle GitHub tokens.

Install only if you intend to run an unattended agent that can modify code and push to a remote dev branch. Use a disposable clone or dedicated worktree, verify repo_url is exactly a GitHub repository you control, avoid passing tokens on the command line, use a fine-grained single-repo token, protect or avoid .env files, and review the first runs before leaving it unattended. Rotate any token used with an untrusted or mistyped repo URL.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
assets/templates/openclaw_autopilot.py:381
Finding
GitHub Token Disclosure to an Arbitrary HTTPS Host<![CDATA[ ## Vulnerability Details **File Location**: `assets/templates/openclaw_autopilot.py:381-385`, with credential-bearing Git operations at `assets/templates/openclaw_autopilot.py:446-477` and `assets/templates/openclaw_autopilot.py:910-1002` **Vulnerability Type**: Insufficient destination validation before transmitting credentials **Risk Level**: High ### Vulnerable Code ```python def inject_token_to_https_url(repo_url: str, token: str) -> str: if not repo_url.startswith("https://"): raise ValueError("Only https:// GitHub URLs are supported for token auth.") safe_token = quote(token, safe="") return repo_url.replace("https://", f"https://x-access-token:{safe_token}@", 1) ``` The resulting credential-bearing URL is used for Git operations: ```python def ensure_repo_synced(cfg: RuntimeConfig, token: str, logger: EventLogger) -> Tuple[bool, Path, str]: cfg.working_root.mkdir(parents=True, exist_ok=True) repo_dir = cfg.working_root / repo_name_from_url(cfg.repo_url) auth_url = inject_token_to_https_url(cfg.repo_url, token) if not (repo_dir / ".git").exists(): code, out = run_cmd(["git", "clone", auth_url, str(repo_dir)], timeout=600) logger.log("repo.clone", ok=(code == 0), output=out[-800:]) if code != 0: return False, repo_dir, "clone_failed" # Remove token from local git config remote. run_cmd(["git", "remote", "set-url", "origin", cfg.repo_url], cwd=repo_dir) ``` It is also used when pushing changes: ```python def commit_and_push( repo_dir: Path, cfg: RuntimeConfig, token: str, audit: AuditResult, logger: EventLogger, ) -> Tuple[bool, str, Optional[str]]: auth_url = inject_token_to_https_url(cfg.repo_url, token) # ... code, out = run_cmd(["git", "push", auth_url, f"{cfg.branch}:{cfg.branch}"], cwd=repo_dir, timeout=300) logger.log("git.push", ok=(code == 0), output=out[-1000:]) ``` Runtime startup only rejects placeholder v ...[truncated 2618 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse repository URLs using `urllib.parse.urlsplit()` rather than string-prefix checks. 2. Require all of the following before any credential is used: - Scheme is exactly `https`. - Hostname is exactly `github.com`. - No preexisting username or password is present. - No unexpected port, fragment, or malformed path is present. - The path conforms to an expected GitHub `owner/repository.git` structure. 3. Apply this validation in the runtime immediately after loading command-line overrides. Do not rely on the optional doctor script. 4. Avoid embedding tokens in URLs. Prefer an ephemeral `GIT_ASKPASS` helper, a properly configured credential helper, or another mechanism that does not expose the token in command arguments or error output. 5. Use a fine-grained GitHub token limited to the target repository, required contents permission, and intended branch workflow. 6. Ensure clone, fetch, and push all use the same validated GitHub destination. 7. Add negative tests for attacker-controlled hosts, deceptive subdomains such as `github.com.attacker.example`, userinfo-based URLs, unexpected ports, and malformed URLs. 8. Rotate any token that may already have been used with an untrusted repository URL. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup_autopilot.py:105
Finding
Repository-Write Token Is Accepted on the Command Line and Stored Without Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup_autopilot.py:49-50` and `scripts/setup_autopilot.py:105-109` **Vulnerability Type**: Insecure plaintext credential handling **Risk Level**: Medium ### Vulnerable Code The setup interface accepts the GitHub token as an ordinary command-line argument: ```python p.add_argument("--token-env", default="GITHUB_TOKEN", help="Token env var name used by runtime") p.add_argument("--token", default=None, help="Optional GitHub token to write into .env") ``` It then writes the token directly to a plaintext file: ```python env_file = output_dir / ".env" if args.token: payload = f"{args.token_env}={args.token}\n" env_file.write_text(payload, encoding="utf-8") print(f"[setup] wrote token to {env_file} ({args.token_env})") elif not env_file.exists(): print(f"[setup] no token written; create {env_file} and set {args.token_env}=<token>") ``` The documented setup workflow encourages this behavior: ```bash python3 scripts/setup_autopilot.py \ --output-dir /path/to/workdir \ --repo-url https://github.com/<owner>/<repo>.git \ --config-profile production \ --token '<your_github_token>' \ --run-doctor \ --run-once \ --force ``` ### Technical Analysis Secrets supplied through a command-line option may be retained in shell history and can be visible through process inspection while the setup command is running. The token is subsequently written using `Path.write_text()` without explicitly setting the file mode to owner-only access. The resulting permissions depend on the process umask and may commonly be `0644`, allowing other local users to read the file in environments where directory traversal is possible. The token remains in plaintext for use by `source .env`. Runtime log masking does not protect: - Shell history. - Process argument listings. - Workspace backups or archives. - Direct reads of an overly permissive `.env` file. - Accidental disclosure by other local tools. Be ...[truncated 1131 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove or deprecate the `--token` command-line option. 2. Accept credentials through a safer channel, such as: - An already populated environment variable. - An interactive `getpass.getpass()` prompt. - A protected file descriptor. - An operating-system keyring or secrets manager. 3. If an `.env` file must be supported: - Create it atomically with mode `0600`. - Use `os.open()` with `O_CREAT | O_EXCL` and mode `0o600`. - Verify and correct permissions on existing files before use. - Refuse symlink targets to reduce unsafe file replacement risks. 4. Warn users if the credential file is group- or world-readable. 5. Ensure `.env` is ignored by Git and excluded from logs, archives, support bundles, and backups where practical. 6. Update README and Skill instructions so examples do not place tokens directly in command lines. 7. Recommend fine-grained, repository-specific tokens with only the permissions required to push to the intended development branch. 8. Document immediate rotation if a token has appeared in shell history or an insecure workspace. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (66)

Credential Access

High
Category
Privilege Escalation
Content
```bash
cd /path/to/workdir
source .env
python3 doctor_autopilot.py --config openclaw_config.json
python3 openclaw_autopilot.py --config openclaw_config.json --once
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cd /path/to/workdir
source .env
python3 doctor_autopilot.py --config openclaw_config.json
python3 openclaw_autopilot.py --config openclaw_config.json --once
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cd /path/to/workdir
source .env
python3 doctor_autopilot.py --config openclaw_config.json
python3 openclaw_autopilot.py --config openclaw_config.json --once
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cd /path/to/workdir
source .env
python3 doctor_autopilot.py --config openclaw_config.json
python3 openclaw_autopilot.py --config openclaw_config.json --once
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
```bash
cd /path/to/workdir
source .env
python3 doctor_autopilot.py --config openclaw_config.json
python3 openclaw_autopilot.py --config openclaw_config.json --once
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description presents a broad operational automation skill that can set up and run an unattended OpenClaw optimization workflow, including failover across CLIs, audit/report gates, fallback reporting, and auto commit/push behavior. The supplied code chunk is much narrower: it is an environment/configuration doctor. It reads a JSON config, validates required keys and repo URL shape, checks presence/version of CLI binaries, probes some login status for Codex and Gemini, and optionally calls the GitHub API to validate a token. This aligns only with the 'diagnose/troubleshoot' portion of the description, not the primary stated capability of deploying and operating the optimization loop. Because the actual code lacks the major advertised behaviors and instead only performs health checks, the description materially overstates and misrepresents what this code chunk does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description describes a complex automation/orchestration system for unattended repository optimization and multi-CLI operation. The supplied code does not implement any of those behaviors. It only installs the skill locally by copying files into a Codex skills directory after basic argument parsing and destination checks. This is a materially different primary purpose, so the description does not accurately represent the code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The description presents a broad operational automation skill for managing OpenClaw across repositories and multiple CLIs, including running loops, failover, gating, and auto-push behavior. The actual code does not deploy, operate, or modify any repository. It only reads existing local log files from a log directory and summarizes them. While this supports diagnosis/inspection of OpenClaw runs, it is only a narrow reporting utility, not the described end-to-end automation operator. Therefore the declared description materially overstates the code's purpose and capabilities.

Credential Access

High
Category
Privilege Escalation
Content
One-round validation:

```bash
source .env
python3 openclaw_autopilot.py --config openclaw_config.json --once --token-env GITHUB_TOKEN
```
Confidence
82% confidence
Finding
The skill explicitly instructs sourcing `.env` and then running automation with a GitHub token environment variable, which indicates credential consumption in a high-privilege unattended workflow. While using env vars is common, the combination of shell execution, network access, auto-commit/push, and insufficient permission scoping makes secret exposure or misuse more consequential if the environment, logs, or subprocesses are not tightly controlled.

Missing User Warnings

High
Confidence
98% confidence
Finding
The workflow performs destructive cleanup (`git clean -fd`) and resets the repository to remote state as part of routine operation without an execution-time warning or confirmation. In a local working tree this can permanently delete untracked files and discard analyst or developer changes, especially dangerous in an unattended loop.

Missing User Warnings

High
Confidence
98% confidence
Finding
Hard reset behavior is built into the sync/rollback flow and discards local changes without user confirmation at the moment it happens. In this skill context, the risk is elevated because resets occur automatically before and after failed attempts, making data loss likely rather than theoretical.

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill is explicitly configured to auto-answer confirmation prompts with `yes`, allowing downstream tools to proceed with actions the user never re-approved at the point of execution. In an unattended repo automation loop, this can authorize destructive edits, dependency installs, or remote operations without meaningful human consent.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
def rollback_repo(repo_dir: Path, cfg: RuntimeConfig, logger: EventLogger) -> None:
    run_cmd(["git", "reset", "--hard", "HEAD"], cwd=repo_dir)
    clean_workspace(cfg, repo_dir, logger, "repo.rollback.clean")
    logger.log("repo.rollback", detail="git reset --hard HEAD && git clean -fd (with preserve list)")


def monitor_cli_process(
Confidence
98% confidence
Finding
`git reset --hard HEAD` is a destructive repository operation that irrevocably discards local modifications, and here it is invoked automatically during rollback. In this skill's unattended repo-management context, repeated automated resets materially increase the risk of data loss and can erase forensic evidence or legitimate in-progress work.

Credential Access

High
Category
Privilege Escalation
Content
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT_DIR"

if [ -f .env ]; then
  # shellcheck disable=SC1091
  source .env
fi
Confidence
94% confidence
Finding
The script blindly sources a local .env file, which executes any shell code contained in that file in the context of the launcher. If an attacker can modify .env or influence the working tree contents, they can achieve arbitrary command execution and expose any credentials loaded there to the spawned automation process and its environment.

Credential Access

High
Category
Privilege Escalation
Content
if [ -f .env ]; then
  # shellcheck disable=SC1091
  source .env
fi

mkdir -p logs
Confidence
88% confidence
Finding
This finding reflects the same unsafe behavior: loading .env via source causes the shell to execute arbitrary content from a repository-local file before starting the Python autopilot. In the context of an unattended GitHub automation loop with commit/push behavior, this increases risk because a poisoned repository or branch could turn configuration loading into persistent remote code execution within an automation environment.

Self-Modification

High
Category
Rogue Agent
Content
action="store_true",
        help="Run doctor_autopilot.py immediately after deploy and return its exit code if failed",
    )
    p.add_argument("--force", action="store_true", help="Overwrite existing files")
    p.set_defaults(fallback_run_tests=None)
    return p.parse_args()
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Credential Access

High
Category
Privilege Escalation
Content
p.add_argument("--cli-order", default="codex,gemini,open-code,claude", help="CLI priority order")
    p.add_argument("--only-cli", default=None, help="Restrict enabled CLIs")
    p.add_argument("--token-env", default="GITHUB_TOKEN", help="Token env var name used by runtime")
    p.add_argument("--token", default=None, help="Optional GitHub token to write into .env")
    p.add_argument("--run-doctor", action="store_true", help="Run doctor after setup")
    p.add_argument("--run-once", action="store_true", help="Run one round after setup")
    p.add_argument("--force", action="store_true", help="Overwrite existing output files")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
p.add_argument("--cli-order", default="codex,gemini,open-code,claude", help="CLI priority order")
    p.add_argument("--only-cli", default=None, help="Restrict enabled CLIs")
    p.add_argument("--token-env", default="GITHUB_TOKEN", help="Token env var name used by runtime")
    p.add_argument("--token", default=None, help="Optional GitHub token to write into .env")
    p.add_argument("--run-doctor", action="store_true", help="Run doctor after setup")
    p.add_argument("--run-once", action="store_true", help="Run one round after setup")
    p.add_argument("--force", action="store_true", help="Overwrite existing output files")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
p.add_argument("--cli-order", default="codex,gemini,open-code,claude", help="CLI priority order")
    p.add_argument("--only-cli", default=None, help="Restrict enabled CLIs")
    p.add_argument("--token-env", default="GITHUB_TOKEN", help="Token env var name used by runtime")
    p.add_argument("--token", default=None, help="Optional GitHub token to write into .env")
    p.add_argument("--run-doctor", action="store_true", help="Run doctor after setup")
    p.add_argument("--run-once", action="store_true", help="Run one round after setup")
    p.add_argument("--force", action="store_true", help="Overwrite existing output files")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
if code != 0:
        return code

    env_file = output_dir / ".env"
    if args.token:
        payload = f"{args.token_env}={args.token}\n"
        env_file.write_text(payload, encoding="utf-8")
Confidence
97% confidence
Finding
This code persists a supplied GitHub token into a predictable .env file in plaintext, which is sensitive credential handling. In this skill's unattended GitHub automation context, such tokens likely enable repository read/write operations, so compromise could lead to unauthorized code pushes, workflow abuse, or access to private source code.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
elif not env_file.exists():
        print(f"[setup] no token written; create {env_file} and set {args.token_env}=<token>")

    run_env = os.environ.copy()
    run_env.update(parse_env_file(env_file))

    if args.run_doctor:
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.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README explicitly promotes unattended repository mutation, automatic branch resets/cleans, and auto-push behavior, but it does not prominently warn that local uncommitted work can be destroyed or that remote changes may be pushed without human review. In the context of an automation skill designed for unattended operation, this omission materially increases the chance of accidental data loss or unintended code changes being propagated.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README instructs users to pass a GitHub token on the command line and states that it will be written into a local .env file, but it does not clearly warn about shell history exposure, file permission risks, or the need to keep the file out of version control. Because this skill automates repo operations and encourages unattended execution, insecure credential handling could expose a write-capable GitHub token and enable repository compromise.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill instructs use of shell, network, file read/write, environment loading, and repository operations, but it declares no explicit tool scope or permission boundaries. In an unattended automation context, that omission increases the chance that an agent executes high-impact actions without adequate user visibility or policy enforcement.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill promotes unattended repository modification and automatic dev-branch commit/push but does not foreground that risk in its user-facing description. In this context, the omission is dangerous because users may invoke the skill without understanding that it can make and publish changes autonomously to a remote repository.