T09 · Insecure Skill Coding Practices
- Location
tools/system-check.py:29- Finding
Destructive restoration targets an incorrectly broad Git repository scope
- Content
View full analysis
Vulnerability Details
File Location:
tools/system-check.py, lines 29 and 34–35, 83–89
Vulnerability Type: Destructive filesystem operation caused by incorrect repository-root calculation
Risk Level: HighVulnerable Code
python # 仓库根目录(Git 仓库在 D:\projects) REPO_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) def run_git(*args): result = subprocess.run( ["git"] + list(args), cwd=REPO_ROOT, capture_output=True, text=True, encoding="utf-8", errors="replace" ) return resultpython def restore(): """恢复所有未提交的变更""" # 恢复已跟踪文件的修改 run_git("checkout", "--", ".") # 删除未跟踪的新文件 run_git("clean", "-fd") print("✅ 已恢复到最后一次合法提交的状态。") return 0Technical Analysis
The script is located at
artifact/tools/system-check.py, butREPO_ROOTis calculated by ascending three directory levels. In the audited layout, this resolves to the parent ofartifact, rather than the Skill directory itself.The
--restoreoperation subsequently runs two destructive Git commands from that incorrectly broad location:git checkout -- .permanently discards modifications to tracked files.git clean -fdpermanently deletes untracked files and directories.
The implementation does not verify that the computed path is the intended Skill repository. It also provides no dry run, file allowlist, interactive confirmation, backup, or return-code validation. If the parent directory is part of a larger Git worktree, restoration can affect unrelated files outside the Skill.
Attack Path
- The Skill is installed or extracted inside a larger Git working tree.
- A user or agent invokes:
bash python tools/system-check.py --restore - The script ascends three directory levels and uses the resulting ancestor as
REPO_ROOT. - `git checkout ...[truncated 1086 chars]
- Remediation
View remediation
Remediation Suggestions
-
Determine the repository root through Git rather than fixed parent traversal:
python result = subprocess.run( ["git", "rev-parse", "--show-toplevel"], cwd=Path(__file__).resolve().parent, capture_output=True, text=True, check=True, ) repo_root = Path(result.stdout.strip()).resolve() -
Verify that the resolved root is exactly the expected Skill directory. Abort if the Git root is an ancestor containing unrelated content.
-
Restrict restoration to an explicit allowlisted path rather than
".". Prefer restoring only files owned by this Skill. -
Run
git clean -ndfirst and display every file that would be deleted. -
Require explicit interactive confirmation or a clearly named destructive flag before running
git clean -fd. -
Consider omitting untracked-file deletion by default. Provide it as a separate operation only when necessary.
-
Check the return code of every Git command and report partial failures accurately. Do not print a success message unless all operations succeed.
-
Document that restoration permanently destroys uncommitted work and recommend creating a backup or stash first.
-
