Back to skill

Security audit

workspace-git-sync

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to perform its stated backup/sync purpose, but it can delete files in a chosen Git repository and push broad workspace contents to a remote without strong safeguards.

Install only if you want a mirror-style backup tool and will point it at a dedicated Git repository. Before use, review the workspace for secrets, verify the repository origin and visibility, avoid force_sync unless you understand the remote-history impact, and do not target an existing project repository with uncommitted or unrelated files.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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/sync_workspace.py:120
Finding

Automatic synchronization may expose workspace secrets to a Git remote

Content
View full analysis

Vulnerability Details

File Location: scripts/sync_workspace.py, lines 120-124, 184-206, and 250-276
Vulnerability Type: Sensitive data exposure through allow-by-default synchronization
Risk Level: High

Vulnerable Code

python
SOURCE_DIR = Path.home() / ".openclaw" / "workspace"
TARGET_DIR = Path(target_repo_path).expanduser().resolve()
DEFAULT_EXCLUDES = {"skills", ".git", "__pycache__", ".DS_Store", "node_modules", ".clawhub"}

if exclude_patterns:
    DEFAULT_EXCLUDES.update(exclude_patterns)
python
for item in SOURCE_DIR.iterdir():
    # Check exclusion list
    if item.name in DEFAULT_EXCLUDES:
        skipped_items.append(item.name)
        continue

    dest = TARGET_DIR / item.name

    try:
        if item.is_file():
            shutil.copy2(item, dest)
            copied_count += 1
            print(f"📄 {item.name}")
        elif item.is_dir():
            # Copy directory and apply exclusion rules
            def ignore_func(dir, contents):
                return [c for c in contents if c in DEFAULT_EXCLUDES]

            shutil.copytree(item, dest, ignore=ignore_func)
            copied_count += 1
            print(f"📁 {item.name}/")
    except Exception as e:
        print(f"⚠️  Copy failed {item.name}: {e}")
python
# git add
subprocess.run(["git", "add", "-A"], check=True, capture_output=True)

# git commit
commit_result = subprocess.run(
    ["git", "commit", "-m", commit_msg],
    capture_output=True,
    text=True,
    check=True
)

# Extract commit hash
commit_hash = ""
match = re.search(r"\[.*? ([a-f0-9]+)\]", commit_result.stdout)
if match:
    commit_hash = match.group(1)[:7]

# git push
if sync_strategy == SyncStrategy.FORCE:
    print(f"⚠️  Using force push (--force-with-lease)")
    push_cmd = ["git", "push", "--force-with-lease", "origin", branch]
else:
    push_cmd = ["git", "push", "origi
...[truncated 2276 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace the allow-by-default copy policy with an explicit allowlist of files and directories suitable for backup.
  2. Recursively exclude common sensitive patterns, including .env*, *.pem, *.key, credential files, token stores, memory records, and conversation archives.
  3. Canonicalize and validate all traversed paths, and avoid following symbolic links to data outside the intended workspace.
  4. Run a secret scanner before staging and again before pushing. Abort when high-confidence credentials are detected.
  5. Display the complete file list, target remote, branch, and repository visibility before the first push.
  6. Require explicit user confirmation for a new remote or when potentially sensitive files are detected.
  7. Support a project-level ignore file with documented recursive glob semantics.
  8. If exposure has already occurred, rotate affected credentials and purge sensitive objects from Git history and all remote references.

T08 · Insecure Dependencies

Warning
Location
README.md:17
Finding

Unpinned placeholder installation source creates a supply-chain risk

Content
View full analysis

Vulnerability Details

File Location: README.md, lines 17-24
Vulnerability Type: Mutable and ambiguous dependency source
Risk Level: Medium

Vulnerable Code

bash
openclaw plugins install workspace-git-sync
bash
# Clone into the skills directory
git clone https://github.com/yourname/workspace-git-sync.git ~/.openclaw/workspace/skills/workspace-git-sync

Technical Analysis

The installation instructions do not identify a verified publisher, version, release artifact, commit hash, signature, or checksum. The manual installation URL contains the placeholder owner yourname, making the authoritative source ambiguous.

Both documented methods retrieve mutable content. If the package name resolves to an unexpected publisher, the placeholder URL is replaced incorrectly, or the selected repository is later compromised, users can install code that differs from the version reviewed during this audit.

Because the installed package includes executable Python code and agent-facing Skill instructions, source substitution can affect both local code execution and agent behavior.

Attack Path

  1. A user follows the installation documentation.
  2. The user resolves the generic package name or replaces the placeholder repository owner without an authoritative identity to verify.
  3. The selected package or repository is attacker-controlled or has been compromised.
  4. The installation retrieves the current mutable contents without integrity verification.
  5. The user or agent invokes the installed Skill.
  6. Malicious instructions or scripts execute with the privileges of the invoking user.

Impact Assessment

A successfully substituted package can perform any operation available to the invoking user and permitted agent tooling, including reading accessible files, modifying workspace content, invoking subprocesses, and transmitting data over available channels.

This project does not itse ...[truncated 187 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace the placeholder URL with the exact repository owned by the verified project publisher.
  2. Document the authoritative registry publisher and package identifier.
  3. Pin installation examples to a signed release, immutable version, or full commit hash.
  4. Publish checksums for release artifacts and explain how users should verify them.
  5. Use signed Git tags or supply-chain provenance attestations.
  6. Avoid recommending installation directly from an unversioned default branch.
  7. Clearly identify the revision corresponding to each audited release.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sync_workspace.py:165
Finding

Synchronization continues into destructive cleanup after a failed Git pull

Content
View full analysis

Vulnerability Details

File Location: scripts/sync_workspace.py, lines 165-198
Vulnerability Type: Unsafe failure handling during destructive synchronization
Risk Level: Medium

Vulnerable Code

python
if pull_before_push and sync_strategy != SyncStrategy.FORCE:
    print(f"\n🔄 Step 3/6: Synchronizing remote changes (git pull --{sync_strategy.value})...")
    pull_result = git_pull(TARGET_DIR, sync_strategy)

    if not pull_result["success"]:
        if pull_result.get("conflict"):
            error_msg = "Merge conflict detected; resolve it manually and retry"
            print(f"❌ {error_msg}")
            return {"status": "error", "message": error_msg, "conflict": True}
        else:
            print(f"⚠️  Pull failed: {pull_result['message']}")
            print(f"    Continuing...")
    else:
        if pull_result.get("skipped"):
            print(f"⏭️  Skipping pull in force mode")
        else:
            print(f"✅ Synchronization complete")
else:
    print(f"\n⏭️  Step 3/6: Skipping git pull")

# Step 4: Clean target directory while preserving .git
print(f"\n🧹 Step 4/6: Cleaning target directory...")
for item in TARGET_DIR.iterdir():
    if item.name == ".git":
        continue
    if item.name in DEFAULT_EXCLUDES:
        continue

    try:
        if item.is_file():
            item.unlink()
            deleted_count += 1
        elif item.is_dir():
            shutil.rmtree(item)
            deleted_count += 1
    except Exception as e:
        print(f"⚠️  Unable to delete {item.name}: {e}")

Technical Analysis

A non-conflict pull failure is treated as a warning rather than a fatal synchronization error. The script then immediately enters a destructive cleanup phase that removes most files and directories from the target repository.

Pull failures can occur because of authentication errors, network outages, missing remote branch ...[truncated 1800 chars]

Remediation
View remediation

Remediation Suggestions

  1. Abort synchronization on every pull failure unless the user has explicitly selected and confirmed an offline or overwrite mode.
  2. Perform all preflight checks before deleting any target content, including remote reachability, branch validation, clean working-tree verification, and push authorization where feasible.
  3. Refuse destructive cleanup when the target contains uncommitted or untracked files unless the user explicitly confirms their removal.
  4. Build the synchronized tree in a temporary staging directory and validate it before atomically replacing repository content.
  5. Stop immediately on deletion or copy failures rather than committing a partially synchronized tree.
  6. Create a recoverable backup or temporary branch before cleanup.
  7. Require explicit confirmation that displays the canonical target path and the files scheduled for deletion.
  8. Return a failure status without committing or pushing whenever any synchronization phase is incomplete.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (24)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill performs bulk deletion of repository contents without any confirmation, dry-run, scope check, or guardrail ensuring the target is a dedicated backup repository. In the context of an agent skill that acts on natural-language instructions, this makes accidental destructive data loss much more likely because users may supply an existing project repository path.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Force mode performs git push --force-with-lease to origin without a strong confirmation barrier. In this skill's context, that can overwrite remote history and propagate accidental repository wiping to collaborators or backups, turning a local mistake into widespread irreversible loss.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
98% confidence
Finding

This skill exposes a high-risk tool parameter combination by invoking git push with --force-with-lease based on a simple mode switch and without meaningful validation of the target remote or branch. In an agent setting, such parameter abuse is dangerous because it enables destructive remote state changes far beyond a typical 'backup' expectation.

Content

Scanner excerpt · scripts/sync_workspace.py (reported line 291)May include surrounding context.

python
if match:
            commit_hash = match.group(1)[:7]
        
        # git push
        if sync_strategy == SyncStrategy.FORCE:
            print(f"⚠️  使用强制推送 (--force-with-lease)")
            push_cmd = ["git", "push", "--force-with-lease", "origin", branch]

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README advertises automatic pull, copy, commit, and push behavior for workspace data without clearly warning that this can overwrite files in the target repository and publish potentially sensitive local workspace contents to a remote. In the context of an automation skill that backs up a whole working directory, omission of these warnings increases the risk of accidental data disclosure or destructive synchronization by users who may treat it as a safe backup tool.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The documented workflow explicitly includes a 'clean old files' step, which implies deletion or replacement of repository contents, but the README provides no safety notice, confirmation step, or recovery guidance. Because this skill operates on a user-specified Git repository and then commits/pushes changes, undocumented cleanup behavior can lead to accidental loss of local files and propagation of the deletion to remote backups.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill documents shell execution and file-writing behavior but does not declare any explicit tool scope such as allowed tools or permissions. That omission weakens least-privilege controls and can let an agent invoke broader capabilities than a user or platform reviewer would expect, especially for a skill that performs filesystem modification and Git network operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill is designed to copy the entire workspace into a Git repository and push it, but the description does not clearly warn that workspace contents may include secrets, tokens, prompts, logs, or private project data that could be sent to a remote origin. In this context, the absence of a prominent warning materially increases the risk of accidental sensitive-data exfiltration.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documented workflow includes clearing the target directory before copying files, yet it does not prominently warn users that existing working-tree files in the target repository can be overwritten or deleted. In a backup/sync skill, this is especially dangerous because a mistaken path or misunderstood target could destroy unrelated local repository contents before the user notices.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Docstrings, status output, errors, and CLI usage messages are written exclusively in Chinese, which effectively forces a specific language for user-facing interaction. The file does not offer locale selection or explain that the skill is intentionally region-specific.

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/sync_workspace.py (reported line 34)May include surrounding context.

python
original_dir = os.getcwd()
    try:
        os.chdir(repo_path)
        result = subprocess.run(
            ["git", "remote", "get-url", remote_name],
            capture_output=True,
            text=True,

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/sync_workspace.py (reported line 51)May include surrounding context.

python
original_dir = os.getcwd()
    try:
        os.chdir(repo_path)
        result = subprocess.run(
            ["git", "branch", "--show-current"],
            capture_output=True,
            text=True,

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/sync_workspace.py (reported line 80)May include surrounding context.

python
return {"success": True, "message": "Force strategy: skip pull", "skipped": True}
        
        print(f"  执行: {' '.join(cmd)}")
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode == 0:
            return {"success": True, "message": "Pull successful", "conflict": False}

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/sync_workspace.py (reported line 88)May include surrounding context.

python
# 检查冲突
            if "conflict" in result.stderr.lower():
                # 中止合并
                subprocess.run(["git", "rebase", "--abort"], check=False, capture_output=True)
                subprocess.run(["git", "merge", "--abort"], check=False, capture_output=True)
                return {"success": False, "message": "Merge conflict", "conflict": True}
            return {"success": False, "message": result.stderr, "conflict": False}

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/sync_workspace.py (reported line 89)May include surrounding context.

python
if "conflict" in result.stderr.lower():
                # 中止合并
                subprocess.run(["git", "rebase", "--abort"], check=False, capture_output=True)
                subprocess.run(["git", "merge", "--abort"], check=False, capture_output=True)
                return {"success": False, "message": "Merge conflict", "conflict": True}
            return {"success": False, "message": result.stderr, "conflict": False}

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill description frames the action as syncing to a local Git repository, but the implementation also performs git pull and git push against origin. This hidden network side effect can exfiltrate workspace contents to a remote repository or modify remote state without the user understanding that remote communication will occur.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code deletes nearly all contents of the target repository before copying workspace files, which is significantly more destructive than a generic 'sync' description implies. In a user-selected repository, this can wipe unrelated tracked or untracked content and then commit that deletion, causing permanent data loss locally and remotely after push.

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/sync_workspace.py (reported line 252)May include surrounding context.

python
os.chdir(TARGET_DIR)
        
        # 配置 git 用户信息(如未配置)
        subprocess.run(["git", "config", "user.email", "kimi-agent@moonshot.cn"], 
                      check=False, capture_output=True)
        subprocess.run(["git", "config", "user.name", "Kimi Agent"], 
                      check=False, capture_output=True)

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/sync_workspace.py (reported line 254)May include surrounding context.

python
# 配置 git 用户信息(如未配置)
        subprocess.run(["git", "config", "user.email", "kimi-agent@moonshot.cn"], 
                      check=False, capture_output=True)
        subprocess.run(["git", "config", "user.name", "Kimi Agent"], 
                      check=False, capture_output=True)
        
        # 检查是否有变更

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/sync_workspace.py (reported line 258)May include surrounding context.

python
check=False, capture_output=True)
        
        # 检查是否有变更
        status_result = subprocess.run(
            ["git", "status", "--porcelain"],
            capture_output=True,
            text=True

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/sync_workspace.py (reported line 275)May include surrounding context.

python
}
        
        # git add
        subprocess.run(["git", "add", "-A"], check=True, capture_output=True)
        
        # git commit
        commit_result = subprocess.run(

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/sync_workspace.py (reported line 278)May include surrounding context.

python
subprocess.run(["git", "add", "-A"], check=True, capture_output=True)
        
        # git commit
        commit_result = subprocess.run(
            ["git", "commit", "-m", commit_msg],
            capture_output=True,
            text=True,

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/sync_workspace.py (reported line 298)May include surrounding context.

python
else:
            push_cmd = ["git", "push", "origin", branch]
        
        subprocess.run(push_cmd, check=True, capture_output=True)
        
        print(f"✅ 提交: {commit_hash}")
        print(f"✅ 推送到 origin/{branch}")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language content of the skill is presented entirely in Chinese, and there is no indication that this locale is optional or required for a region-specific purpose. Per the policy, forcing a specific language without user opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The force-sync helper understates risk by describing the action as overwriting remote state, while the actual workflow also skips pull, mirrors local workspace into the target repo after deletion, and force-pushes the result. This mismatch can mislead users into invoking a much more destructive operation than they expect.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.