Back to skill

Security audit

Gumroad Admin Publisher

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherently built for Gumroad administration, but its batch publishing helper can upload local files named in an editable manifest and can publish products before verification.

Review the batch publishing script before installing. Use dry runs and one-product batches, keep manifests generated and stored locally, do not run publish on manifests from untrusted sources, and avoid --publish until upload path validation and verify-before-publish ordering are fixed.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gumroad_batch_publish.py:130
Finding

Untrusted Manifest Paths Permit Arbitrary Local File Upload

Content
View full analysis
dict[str, Any]: return json.loads(path.read_text(encoding="utf-8")) ``` ```python def create_product(record: dict[str, Any], *, publish: bool, dry_run: bool) -> dict[str, Any]: cmd = [ "products", "create", "--name", record["title"], "--price", str(record["price"]), "--description", record.get("description") or "", "--custom-summary", record.get("custom_summary") or "", "--file", record["file"], "--file-name", record.get("file_name") or Path(record["file"]).name, "--yes", ] if record.get("cover_image"): cmd += ["--cover-image", record["cover_image"]] if record.get("thumbnail"): cmd += ["--thumbnail", record["thumbnail"]] ``` ```python def cmd_publish(args: argparse.Namespace) -> None: if not args.yes and not args.dry_run: raise SystemExit("Refusing live batch publish without --yes after explicit user confirmation.") path = Path(args.manifest) manifest = load_manifest(path) records = selected_records(manifest, args.limit, args.only_sku) results = [] for record in records: result = create_product(record, publish=args.publish, dry_run=args.dry_run) results.append({"sku": record.get("sku"), "product_id": record.get("product_id"), "verified": record.get("verified"), "response": result if args.dry_run else None}) save_manifest(path, manifest) ``` ### Technical Analysis The `publish` operation treats an existing JSON manifest as trusted input. The `file`, `cover_image`, and `thumbnail` values are passed directly to the authenticated Gumroad CLI without confirming ...[truncated 1953 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gumroad_batch_publish.py:151
Finding

Products Can Be Published Before Verification Completes

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (3)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 136)May include surrounding context.

md
Before publishing:

1. Ensure the skill contains no credentials, real access tokens, account secrets, private paths, or temporary public URLs.
2. Keep personal machine details in `TOOLS.md`, not the skill.
3. Validate scripts with `python -m py_compile scripts/gumroad_batch_publish.py`.
4. Test read-only CLI commands: `gumroad user --json`, `gumroad products list --json`.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill instructs the agent to use shell commands, read local files, and write local state/manifests, but it declares no explicit tool scope or permission boundary. That creates an authorization gap where an agent may execute high-impact commerce and filesystem operations without a machine-readable least-privilege policy, increasing the chance of unintended destructive actions or misuse.

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

python
cmd = ["gumroad", *args, "--json", "--no-input", "--non-interactive"]
    if dry_run:
        cmd.append("--dry-run")
    proc = subprocess.run(cmd, text=True, capture_output=True)
    if proc.returncode != 0:
        raise RuntimeError(json.dumps({"cmd": redact_cmd(cmd), "stderr": proc.stderr.strip(), "stdout": proc.stdout.strip()}, indent=2))
    if not proc.stdout.strip():

Static analysis

No suspicious patterns detected.