Back to skill

Security audit

Openclaw Github Sync

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it advertises, but it has broad sync and pull-back powers that can expose private agent context or overwrite active instructions without enforced review.

Install only if you control the private repository and are comfortable syncing agent memory, skill code, and instruction files. Before first use, narrow references/export-manifest.txt to sanitized paths such as memory/public/ and specific skills, treat secret scanning as a last check rather than proof of safety, avoid automating pull, use PULL_DRY_RUN and manual diffs before any pull, and do not put executable shell content in references/.env.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
references/export-manifest.txt:5
Finding
Broad agent context is uploaded without comprehensive sensitive-data inspection<![CDATA[ ## Vulnerability Details **File Location**: `references/export-manifest.txt:5-15`; `scripts/sync.sh:45-62, 81-99, 143`; `scripts/scan_secrets.py:20-46, 82-103` **Vulnerability Type**: Incomplete sensitive-data validation before network transmission **Risk Level**: High ### Vulnerable Code `references/export-manifest.txt:5-15`: ```text AGENTS.md IDENTITY.md SOUL.md TOOLS.md USER.md # Skills (add more as you create them) skills/ # Memories memory/ ``` `scripts/sync.sh:45-62`: ```bash while IFS= read -r path; do # strip comments/blank path="${path%%#*}" path="$(echo "$path" | xargs || true)" [[ -z "$path" ]] && continue src="$WORKSPACE_DIR/$path" if [[ -d "$src" ]]; then mkdir -p "$SYNC_REPO_DIR/$path" # Preserve directory paths exactly as listed in the manifest. rsync -a --delete --exclude '.git/' "$src/" "$SYNC_REPO_DIR/$path/" elif [[ -f "$src" ]]; then mkdir -p "$SYNC_REPO_DIR/$(dirname "$path")" rsync -a "$src" "$SYNC_REPO_DIR/$path" else echo "WARN: not found: $path" >&2 fi done < "$MANIFEST" ``` `scripts/scan_secrets.py:33-46, 82-103`: ```python SCAN_EXTS = { ".md", ".txt", ".json", ".yml", ".yaml", ".js", ".ts", ".php", ".sh", ".py", ".env", "", # extensionless } SKIP_DIR_NAMES = {".git", "node_modules", "vendor", ".archive"} SKIP_FILE_NAMES = {"hosts.yml", "known_hosts", "known_hosts.old"} ``` ```python def should_scan(p: Path) -> bool: if p.name in SKIP_FILE_NAMES: return False # Skip very large files try: if p.stat().st_size > 2_000_000: return False except FileNotFoundError: return False ext = p.suffix.lower() if ext not in SCAN_EXTS: # still scan extensionless small text files return False if looks_binary(p): return False return True ``` `scripts/sync.sh:143`: ```bash git -C "$SYNC_REPO_DIR" push -u origin main ``` ### Technical Analysis The de ...[truncated 2482 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the default `memory/` export with a narrowly curated path such as `memory/public/`. 2. Require users to enumerate individual Skills or files instead of exporting the complete `skills/` tree. 3. Fail closed when an allowlisted file cannot be scanned because it is binary, oversized, unreadable, or uses an unsupported type. 4. Maintain a strict permitted-extension and maximum-size policy for remotely synchronized content. 5. Add entropy-based detection and structured checks for additional credential formats, private keys, cookies, session tokens, connection strings, and personal data. 6. Scan the exact Git index or commit tree that will be pushed, not merely a broad working-directory view. 7. Present a complete first-run inventory of files and byte sizes and require explicit user approval before the initial upload. 8. Validate that the destination is an approved private repository controlled by the user before pushing. 9. Document clearly that heuristic scanning cannot establish that content is non-sensitive. ]]>

T01 · Skill Instruction Hijacking

Error
Location
scripts/pull.sh:43
Finding
Untrusted remote content can overwrite active Agent instructions and introduce executable Skill content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pull.sh:43-46, 64-91, 93-137`; `scripts/bootstrap.sh:18-40` **Vulnerability Type**: Unsafe retrieval and installation of instruction-bearing and executable remote content **Risk Level**: High ### Vulnerable Code `scripts/pull.sh:43-46`: ```bash if git -C "$SYNC_REPO_DIR" ls-remote --exit-code --heads origin main >/dev/null 2>&1; then git -C "$SYNC_REPO_DIR" fetch origin main git -C "$SYNC_REPO_DIR" reset --hard origin/main ``` `scripts/pull.sh:64-91`: ```bash # 1) Pull ALL skills (full directory contents) -> workspace/skills if [[ -d "$SYNC_REPO_DIR/skills" ]]; then mkdir -p "$WORKSPACE_DIR/skills" rsync -a "${DRY[@]}" "${DEL[@]}" \ --exclude '.git/' \ --exclude 'node_modules/' \ --exclude '__pycache__/' \ --exclude '*.pyc' \ "$SYNC_REPO_DIR/skills/" "$WORKSPACE_DIR/skills/" fi # 2) Pull ALL markdown files anywhere in the sync repo (excluding .git, node_modules) # into the workspace at the same relative paths. # This overwrites workspace copies where paths collide. RSYNC_FILTERS=( --exclude '.git/' --exclude 'node_modules/' --exclude '__pycache__/' --exclude '*.pyc' --include '*/' --include '*.md' --exclude '*' ) rsync -a "${DRY[@]}" \ "${RSYNC_FILTERS[@]}" \ "$SYNC_REPO_DIR/" "$WORKSPACE_DIR/" ``` `scripts/pull.sh:108-137`: ```bash src_base="$SYNC_REPO_DIR/agents/$agent_id" [[ ! -d "$src_base" ]] && continue # Agent skills (full directory) if [[ -d "$src_base/skills" ]]; then mkdir -p "$agent_ws/skills" rsync -a "${DRY[@]}" "${DEL[@]}" \ --exclude '.git/' \ --exclude 'node_modules/' \ --exclude '__pycache__/' \ --exclude '*.pyc' \ "$src_base/skills/" "$agent_ws/skills/" fi # Agent markdown (md-only), excluding skills/ (already handled). AGENT_MD_FILTERS=( --exclude 'skills/' --exclude '.git/' --exclude 'node_modules/' --exclude '__pycache__/' --exclude '*.pyc' --include '*/' --include '*.md' --exc ...[truncated 3593 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Fetch remote changes into a dedicated quarantine directory rather than directly into an active workspace. 2. Make dry-run and diff review mandatory before any write operation. 3. Display the source repository, exact commit hash, author, changed paths, and content diff, then require explicit confirmation. 4. Require signed commits from an allowlist of trusted signing identities or pin an approved commit hash. 5. Reject executable files and configuration files such as `.env` during pull unless they receive separate explicit approval. 6. Limit inbound synchronization to narrowly defined data-only paths; do not restore complete Skill directory trees by default. 7. Require independent approval before modifying `AGENTS.md`, `IDENTITY.md`, `SOUL.md`, `USER.md`, `TOOLS.md`, or `SKILL.md`. 8. Replace `source "$env_path"` with a strict data parser that accepts only known variable names and inert values. 9. Validate all destination paths, including agent workspace paths obtained from `openclaw.json`, before writing. 10. Preserve backups and support atomic rollback of every applied pull. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/scan_secrets.py:137
Finding
Secret scanner discloses detected credentials through logs and plaintext report files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scan_secrets.py:137-149`; `scripts/sync.sh:84-95`; `scripts/nightly_sync.sh:29-40` **Vulnerability Type**: Plaintext sensitive-data exposure **Risk Level**: Medium ### Vulnerable Code `scripts/scan_secrets.py:137-149`: ```python for label, rx in PATTERNS: for m in rx.finditer(text): # approximate line number line_no = text[: m.start()].count("\n") + 1 snippet = m.group(0) if len(snippet) > 120: snippet = snippet[:120] + "…" findings.append((label, rel, line_no, snippet)) if not findings: print("OK: no likely secrets found") return 0 print("POTENTIAL SECRETS DETECTED — refusing to commit/push") print("Review and remove/redact these before syncing:") for label, rel, line_no, snippet in findings[:200]: print(f"- {label}: {rel}:{line_no}: {snippet}") ``` `scripts/sync.sh:84-95`: ```bash if [[ -x "$SCAN_SCRIPT" ]]; then set +e SCAN_OUT=$(SCAN_IGNORE_FILE="$SCAN_IGNORE_FILE" "$SCAN_SCRIPT" "$SYNC_REPO_DIR" 2>&1) SCAN_CODE=$? set -e echo "$SCAN_OUT" if [[ $SCAN_CODE -eq 3 ]]; then # Contract: exit 3 means secret-like material detected. exit 3 elif [[ $SCAN_CODE -ne 0 ]]; then echo "WARN: secret scan failed (code $SCAN_CODE); refusing to commit" >&2 exit 4 fi ``` `scripts/nightly_sync.sh:29-40`: ```bash set +e OUTPUT=$(SYNC_REMOTE="$SYNC_REMOTE" WORKSPACE_DIR="$WORKSPACE_DIR" SYNC_REPO_DIR="$SYNC_REPO_DIR" "$SCRIPT_DIR/sync.sh" 2>&1) CODE=$? set -e echo "$OUTPUT" if [[ $CODE -eq 3 ]]; then # Secret scan failed (see sync.sh contract). printf "%s\n" "$OUTPUT" > "$REPORT_PATH" echo "SECRET_ALERT: potential secrets detected; see $REPORT_PATH" exit 3 fi ``` The default report location is established at `scripts/nightly_sync.sh:16`: ```bash REPORT_PATH="${REPORT_PATH:-$WORKSPACE_DIR/memory/secret-scan-alert.txt}" ``` ### Technical Analysis When a secret is detected, the scanner stores the com ...[truncated 1977 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never print the complete matched secret. 2. Report only the finding category, relative path, line number, and a non-reversible fingerprint. 3. If limited context is necessary, redact all but a small fixed prefix and suffix while avoiding private-key body output entirely. 4. Avoid storing scanner output under any exported workspace path. 5. Place local reports in a dedicated non-exported directory with permissions restricted to the owner, such as mode `0600`. 6. Configure scheduled jobs and Agent tooling to suppress sensitive scanner output from centralized logs. 7. Remove stale reports automatically after the issue is resolved. 8. Add a regression test asserting that known sample secrets never appear in stdout, stderr, or report contents. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill markets itself primarily as exporting non-sensitive context for remote review, but the content also documents manual pull functionality that can import remote content back into the workspace, overwrite local files, and potentially delete files. Because pulled content can modify skills, markdown, and persona files that influence future agent behavior, under-describing this bidirectional trust boundary materially increases the risk of prompt injection, persistence, or destructive workspace tampering.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill markets itself primarily as exporting non-sensitive context for remote review, but the content also documents manual pull functionality that can import remote content back into the workspace, overwrite local files, and potentially delete files. Because pulled content can modify skills, markdown, and persona files that influence future agent behavior, under-describing this bidirectional trust boundary materially increases the risk of prompt injection, persistence, or destructive workspace tampering.

Credential Access

High
Category
Privilege Escalation
Content
local var i
  local -a had_values values names

  env_path="$(openclaw_github_sync_default_skill_dir)references/.env"

  [[ -f "$env_path" ]] || return 0
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
local var i
  local -a had_values values names

  env_path="$(openclaw_github_sync_default_skill_dir)references/.env"

  [[ -f "$env_path" ]] || return 0
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if not line or line.startswith("#"):
            continue
        rules.append(line)
    return rules


def is_ignored(rel_path: str, rules: list[str]) -> bool:
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
done < "$MANIFEST"

# Ensure we never accidentally commit workspace git metadata.
rm -rf "$SYNC_REPO_DIR/.git"/.openclaw 2>/dev/null || true

# Generate/update sync repo README from template + current change status.
README_TEMPLATE="$SCRIPT_DIR/../references/README_TEMPLATE.md"
Confidence
95% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Vague Triggers

Medium
Confidence
94% confidence
Finding
The README tells users to invoke installation with a natural-language phrase that is broad enough to be repeated in normal conversation, which can unintentionally trigger skill installation or setup actions. In an agent environment, ambiguous trigger phrases increase the chance of unauthorized or accidental execution, especially when the described setup includes creating repositories and scheduling nightly automation.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill metadata declares required binaries and environment variables but does not declare any explicit tool scope or allowed-tools constraints, despite clearly requiring file read/write and environment access to operate. In an agent ecosystem, missing permission boundaries increases the chance the skill will run with broader-than-necessary capabilities, making misuse or unintended file access more likely.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script unconditionally sources a local references/.env file when managed variables are unset, which executes any shell code contained in that file in the current process. Because .env content is treated as code rather than parsed as data, a modified or malicious .env can run arbitrary commands during bootstrap, making this a real code-execution risk rather than just configuration loading.

Static analysis

No suspicious patterns detected.