T03 · Remote Payload Retrieval and Execution
- Location
SKILL.md:32- Finding
Mutable Remote Python Payload Download in Skill Installation Instructions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly a codebase metrics tool, but its install instructions and CI helper create avoidable code-execution risks that users should review before installing.
Prefer the bundled reviewed code or a pinned release instead of the documented curl-from-main install. Run this only against repositories you trust, or use an isolated environment with no secrets for untrusted code. Treat generated HTML reports and .codebase-snapshots as potentially sensitive project metadata.
SKILL.md:32Mutable Remote Python Payload Download in Skill Installation Instructions
README.md:34Mutable Remote Python Payload Download in README Installation Instructions
codebase_inspector.py:183Stored HTML Injection Through Unescaped Directory and File Names
ci/verify_product.py:36Verification Harness Executes Python Files From Untrusted Product Directories
The supplied code does not perform codebase analysis or any of the advanced reporting/export features described. Its primary purpose is a basic CI/deploy check for skill packaging metadata, specifically validating SKILL.md frontmatter and presence of a tool file. While this loosely fits 'CI/CD integration,' the overall declared description materially overstates and misrepresents the actual behavior.
The supplied code does not implement the advanced reporting and analytics features described. Instead, it is a narrow validation harness for product/skill folders used in CI or local checks. It performs structural/documentation checks, Python compilation checks, test detection/execution, a basic regex-based secret scan, and a deploy-readiness invocation. CI integration is partially consistent, but the primary purpose and most named capabilities in the description—HTML reports, git diffs, trend tracking, SVG badges, and CSV export—are absent. Therefore the description materially overstates and misrepresents the code's actual behavior.
The overall primary purpose matches: this is a codebase analysis/reporting CLI with HTML output, CSV export, trend snapshots, and diff-like comparison. However, several declared capabilities are overstated or inaccurate. The 'git-aware diffs' claim is not supported because no git APIs, commands, or repository metadata are used; the diff feature is a plain directory-to-directory metrics comparison. The 'SVG badges' claim is also inaccurate because the tool does not emit SVG data, only a URL to an external badge service. Finally, 'CI/CD integration' is not present in the code beyond being a generic command-line tool that could be used in CI manually. These are material description-to-behavior mismatches, even though much of the rest of the description is accurate.
Without declared permissions the skill's intent is opaque and cannot be validated.
This finding correctly identifies that the verification harness executes arbitrary Python files from the target product directory via the self-test mechanism. In the context of a codebase inspection/verification skill, that is especially risky because the tool is expected to process potentially adversarial repositories, so verification becomes a direct arbitrary-code-execution vector.
This verifier explicitly executes product-supplied Python files to check for a self-test command. Because the target folder is untrusted input in a codebase-inspection skill, an attacker can place a malicious script that performs arbitrary code execution during verification, turning analysis/CI into an execution sink.
def has_self_test(fp):
r = subprocess.run([sys.executable, fp, "self-test"], capture_output=True, text=True, timeout=30)
return r.returncode == 0 and "PASS" in r.stdout
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
all_ok &= axis(False, "frontmatter (no SKILL.md)")
all_ok &= axis(False, "docs (no SKILL.md)")
# 3 compiles
comp_ok = all(subprocess.run([sys.executable, "-m", "py_compile", fp],
capture_output=True).returncode == 0 for fp in files)
all_ok &= axis(comp_ok, "compiles (py_compile all .py)")
# 4 self-test (any of 3 valid forms)
The harness enumerates test files in the analyzed folder and runs them as Python programs, which grants untrusted repository contents code execution during verification. Because this skill is intended for inspection and CI integration, attackers can weaponize apparently legitimate test files to compromise the verification environment.
The verifier discovers test_*.py and *_test.py files in the analyzed folder and runs them directly. In an untrusted product or pull-request context, a malicious contributor can embed arbitrary code in a test file and gain code execution in CI or on the analyst's machine, potentially exposing credentials, modifying workspace contents, or pivoting further.
tests = [os.path.join(folder, f) for f in os.listdir(folder)
if (f.startswith("test_") or f.endswith("_test.py")) and f.endswith(".py")]
if tests:
st_ok = all(subprocess.run([sys.executable, t], capture_output=True, text=True,
timeout=30).returncode == 0 for t in tests)
st_note = f"{len(tests)} test_*.py"
elif re.search(r"(?im)^test\s*:", skill_txt):
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# 7 deploy-ready
ci = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ci_check.py")
if os.path.isfile(ci) and os.path.isfile(skill):
r = subprocess.run([sys.executable, ci], cwd=folder, capture_output=True, text=True)
all_ok &= axis(r.returncode == 0, "deploy-ready (ci/ci_check.py PASS)")
else:
all_ok &= axis(True, "deploy-ready (skipped)")
The module docstring and manifest description advertise 'git-aware diffs', and the CLI description repeats that claim at L346. However, the implemented diff path at L310-L337 simply analyzes two directories and compares file/line totals by language, with no interaction with git metadata, repositories, commits, or diffs. This is a direct description-behavior mismatch rather than an implementation detail.
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.
# ── analysis engine ──────────────────────────────────────────────────────
def analyze(path, exclude_dirs=None):
"""Walk directory and return structured analysis."""
stats = defaultdict(lambda: {"files": 0, "lines": 0, "blank_lines": 0,
"comment_lines": 0, "code_lines": 0})
file_list = []
The HTML report interpolates repository-derived values such as file names and directory names directly into HTML without escaping. If a scanned repository contains file names or paths with HTML-special characters, opening the generated report could trigger stored HTML/JavaScript injection in the viewer's browser, and even absent script execution the report exposes repository metadata that may be sensitive when shared.
The snapshot logic creates a hidden directory inside the analyzed project and stores JSON snapshots containing directory paths, timestamps, file counts, and largest file listings. Although saving is intentional when --snapshot is used, the code lacks clear user disclosure that historical metadata about the codebase will be retained on disk inside the target directory.
No suspicious patterns detected.