T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/git_manager.py:458- Finding
Commit operation stages files outside the declared configuration allowlist
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill has a coherent local Git configuration-management purpose, but it handles OpenClaw credentials and restores with under-scoped safeguards that can expose or overwrite sensitive local data.
Install only if you are comfortable with a local tool modifying and committing files under ~/.openclaw. Before using commit or restore, back up ~/.openclaw, avoid tracking live credentials, review the exact files being staged, and treat diff/log/commit-message output as potentially sensitive.
scripts/git_manager.py:458Commit operation stages files outside the declared configuration allowlist
scripts/git_manager.py:56Heuristic secret detection can commit unsupported credentials in plaintext
scripts/git_manager.py:158Raw diff and commit-message output can disclose secret values
scripts/git_manager.py:298Secret redaction destructively overwrites live credential and configuration files
The skill explicitly includes a destructive command path using git reset --hard <commit>, which can irreversibly discard uncommitted local changes. Even with a note about requiring explicit user confirmation, encoding this operation in the skill creates a high-risk avenue for destructive state changes, especially if commit parameters or user intent are misparsed by an agent.
Restore modes:
- **Full tree restore**: `git checkout <commit> -- .` (all tracked files)
- **Single file restore**: `git checkout <commit> -- path/to/file`
- **Hard reset** (destructive): `git reset --hard <commit>` — only if user explicitly says "hard reset"
Do not:
- Perform destructive restores (hard reset, force checkout) without explicit user confirmation
The trigger phrases include very generic terms such as "restore," "rollback," and "what changed," which are likely to occur in ordinary conversation outside the intended git/config-management context. In an agent skill that can commit or restore configuration state, accidental activation could lead to unintended version-control operations or rollback workflows being initiated at the wrong time.
The skill instructs use of shell commands and file-modifying operations but does not declare any explicit tool scope or permissions boundaries. In an agent system, this creates an authorization gap: the skill can induce broad filesystem and command execution behavior without a machine-readable restriction, increasing the chance of overbroad access, unsafe invocation context, or privilege misuse.
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.
2. If the user names a specific file: restore only that file to the commit's version
3. Show a preview diff first: what will change from current state
4. Require user confirmation before overwriting current files
5. After restore, create an automatic recovery commit marking the restore point:
`config: restore to <hash> (<description>)`
6. Report which files were changed and the new HEAD commit
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def git(*args, cwd=REPO_DIR, capture=True):
if capture:
result = subprocess.run(
["git"] + list(args), cwd=cwd, capture_output=True, text=True,
)
return result.stdout.strip(), result.stderr.strip(), result.returncode
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
)
return result.stdout.strip(), result.stderr.strip(), result.returncode
else:
result = subprocess.run(["git"] + list(args), cwd=cwd)
return "", "", result.returncode
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.
if not found:
return False, []
# Write redacted version
with open(full, "w") as f:
f.write(redacted)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def run_doctor():
"""Run openclaw gateway doctor and return (ok, output)."""
result = subprocess.run(
["openclaw", "gateway", "doctor"],
cwd=OPENCLAW_DIR,
capture_output=True,
The commit workflow stages every changed file reported by git status except nested git directories, rather than restricting operations to TRACKED_PATHS. In a configuration directory that may also contain tokens, logs, transient data, or attacker-planted files not covered by .gitignore, this can persist unintended sensitive or malicious content into version history.
Before staging, the script rewrites credential-bearing files in place to redact suspected secrets, changing the user's working configuration without prior confirmation or creating a backup. This can silently break live credentials, destroy original secret values, and produce denial-of-service or recovery problems if the redaction regex overmatches or the user expected a non-destructive commit flow.
The restore path accepts an arbitrary --file value and uses git checkout <target> -- <file> or restores the entire tree, without enforcing that the path is one of the intended OpenClaw configuration targets. This enables destructive modification of any file in the repository, which is especially risky because the repository root is ~/.openclaw, a directory likely to contain security-sensitive material beyond the intended config set.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
diff_cmd += ["--", file_path]
else:
diff_cmd += [target, "--"]
diff_out = subprocess.run(diff_cmd, cwd=REPO_DIR,
capture_output=True, text=True)
what = file_path or "(all tracked files)"
The restore flow performs destructive checkout operations and then automatically runs a validation subprocess; on force/undo paths, the safety confirmation is bypassed. That combination can overwrite repository files and trigger additional side effects with reduced user awareness, increasing the chance of accidental data loss or unintended operational changes.
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.
restore_p.add_argument("--undo", action="store_true", help="Undo last restore")
restore_p.add_argument("--file", help="Restore specific file only")
restore_p.add_argument("-f", "--force", action="store_true",
help="Skip confirmation")
args = parser.parse_args()
cmd = args.command
The skill description is written entirely in Chinese while the listed trigger phrases are in English, and there is no statement that users may choose their preferred language or that the skill is intentionally region-specific. This can be read as a locale/language policy issue because the skill does not document language expectations or provide opt-in choice.
The inline comment states that the script logs 'actual secret hashes (not the secrets themselves) for audit', but the appended log entries contain only file, type, timestamp, and a static commit hint. This is an active contradiction between documentation and implementation, which could mislead reviewers about the audit trail's strength.
The manifest frames this skill as a Git manager for tracking, comparing, committing, and rolling back configuration changes, but the code also executes openclaw gateway doctor after restore. Running service diagnostics is an additional operational capability that is not clearly justified by a version-control-focused skill description.
The dependency is specified as PyYAML>=6.0 without an upper bound or exact pin, which makes builds non-reproducible and allows different environments to resolve to different releases. This increases supply-chain risk and can unexpectedly introduce vulnerable or breaking versions over time, even if it is not an immediately exploitable flaw by itself.
PyYAML>=6.0
Because the manifest does not pin a specific PyYAML version, it is impossible to verify from this file alone whether deployment will use a release affected by known PyYAML advisories. In a skill that manages configuration data, YAML parsing may plausibly be used on user- or repo-controlled content, which makes ambiguity around parser version more security-relevant than in a purely internal library.
No suspicious patterns detected.