T09 · Insecure Skill Coding Practices
- Location
scripts/gpt_review.py:88- Finding
Weak URL Validation Can Disclose Article Content to an Attacker-Controlled Website
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a purpose-aligned ChatGPT review automation, but its browser automation and local helper discovery create real risks of sending article content to the wrong page or running an untrusted local script.
Install only if you are comfortable giving the skill access to a CDP-enabled Brave session logged into ChatGPT and sending reviewed article content to ChatGPT. Avoid confidential, unpublished, personal, or regulated content unless you have explicit approval. Use a trusted absolute --cdp-script path, start Brave only for this workflow, close unrelated tabs, and review output paths because existing files can be overwritten.
scripts/gpt_review.py:88Weak URL Validation Can Disclose Article Content to an Attacker-Controlled Website
scripts/gpt_review.py:34Relative Dependency Auto-Discovery Allows Local Tool Hijacking
SKILL.md:69Unpinned Runtime Dependency Installation Creates Supply-Chain Exposure
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
def main():
parser = argparse.ArgumentParser(description="Build GPT review prompt from template")
parser.add_argument("--article", required=True, help="Path to article file")
parser.add_argument("--output", required=True, help="Output prompt file")
parser.add_argument("--context", default="文章",
help="Content type: 播客/B站视频/文章 (default: 文章)")
parser.add_argument("--template", default=DEFAULT_TEMPLATE,
The skill automates sending article content to ChatGPT through a browser session and saves the model output to a file, but the skill description does not clearly warn users that their content will leave the local workflow and be disclosed to a third-party service. This can lead to accidental transmission of sensitive, unpublished, or regulated material because users may invoke the skill without understanding the data-sharing and persistence implications.
The markdown content is entirely written in Chinese and presents the skill guidance in that language without any indication that users may choose another language or that the skill is intentionally region-specific. Under the policy criteria, a fixed language requirement without opt-in or justification is a natural-language locale policy violation.
The CLI sets the default context to "文章" and the supported context values in help text are Chinese-only, while the generated suffix content is also entirely Chinese. This creates a language/locale constraint by default rather than offering a neutral default or explicit language choice.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if not script:
print("Error: cdp_exec.py not found", file=sys.stderr)
return None
result = subprocess.run(
["python3", script, "--port", str(port), "eval", tab_id, js_code,
"--timeout-ms", str(timeout_ms)],
capture_output=True, text=True, timeout=30
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.
def list_tabs(port=9222):
"""List open browser tabs."""
try:
with urllib.request.urlopen(f"http://localhost:{port}/json/list", timeout=5) as resp:
return json.loads(resp.read().decode("utf-8"))
except Exception as e:
print(f"Error listing tabs: {e}", file=sys.stderr)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
# Open a new tab via system command
print("Opening new ChatGPT tab...", file=sys.stderr)
subprocess.run(["open", "-a", "Brave Browser", "https://chatgpt.com"],
capture_output=True, timeout=5)
time.sleep(8)
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.
def close_tab(tab_id, port=9222):
"""Close a browser tab."""
try:
with urllib.request.urlopen(
f"http://localhost:{port}/json/close/{tab_id}", timeout=5
) as resp:
result = resp.read().decode("utf-8")
The script reads arbitrary prompt content from --prompt or --prompt-file and automatically sends it to ChatGPT, but it provides no explicit disclosure warning, confirmation gate, or filtering for sensitive data. In an agent-skill context, this can unintentionally exfiltrate proprietary, personal, or secret material to an external third-party service because the transfer is built into the tool's normal workflow.
The script writes the extracted model response directly to a user-specified path using write mode, which will overwrite an existing file without confirmation. While this is not remote code execution, it can cause local data loss or clobber important files if the output path is mistaken, maliciously supplied by a calling workflow, or points to a sensitive location.