T09 · Insecure Skill Coding Practices
- Location
lib/router.py:36- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a real web/video downloader, but it can fetch arbitrary URLs and reuse browser login cookies without strong warnings or scope limits.
Review before installing. Use it only with URLs you trust, avoid --cookies-browser unless you understand it can use your logged-in browser sessions, run it in an isolated environment or dedicated browser profile, and constrain output directories and network access where possible.
lib/router.py:36Unrestricted URL Fetching Enables Server-Side Request Forgery
lib/article.py:262Unbounded Remote Resource Processing Can Exhaust Memory and Disk
SKILL.md:25Unpinned Third-Party Dependencies and Browser Assets Create Supply-Chain Risk
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
--quality N Video quality: 1080, 720, 480 (default: 1080) --method METHOD Force method: scrapling, camoufox, ytdlp, feishu --selector CSS Force CSS selector for content extraction --urls-file FILE File with URLs (one per line, # for comments) --audio-only Extract audio only (video downloads) --no-images Skip image download (articles) --cookies-browser NAME Browser for cookies (e.g., chrome, firefox)
## How It Works
URL → router.py (domain matching) → handler ├── article.py (scrapling GET → browser → camoufox) ├── feishu.py (virtual scroll + authenticated image fetch) └── video.py (yt-dlp wrapper)
Articles are converted to Markdown with images downloaded locally. Videos are downloaded as MP4 (or MP3 with `--audio-only`).
## Dependencies
Install only what you need:
The declared description presents the skill as a web fetcher/downloader for articles and videos across multiple services. However, the supplied code chunk is the Mozilla/Arc90-style Readability parser: it accepts an HTMLDocument object and extracts readable article content and metadata from that document. Its functions focus on DOM cleanup, content scoring, metadata extraction, image/lazy-load handling, and preserving embedded video elements when cleaning content. There is no code for HTTP requests, URL fetching, authentication, platform integration, saving content, or media/video downloading. Therefore the code’s actual behavior is a content-extraction helper, not a web-fetching/downloading skill as declared.
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
--quality N Video quality, e.g. 1080, 720 (default: 1080) --method METHOD Force method: scrapling, camoufox, ytdlp, feishu --selector CSS Force CSS selector for content extraction --urls-file FILE File with URLs (one per line, # for comments) --audio-only Extract audio only (video downloads) --no-images Skip image download (articles) --cookies-browser NAME Browser for cookies (e.g., chrome, firefox)
## Platform Notes
### WeChat (mp.weixin.qq.com)
- Images use `data-src` attribute with `mmbiz.qpic.cn` URLs
- Visible `<img>` tags contain SVG placeholders (lazy loading)
- Image download requires `Referer: https://mp.weixin.qq.com/` header
- Scrapling GET usually works; no browser needed
### Feishu (*.feishu.cn)
- Uses virtual scroll — content blocks are rendered on-demand
- The fetcher scrolls through the entire document, collecting `[data-block-id]` elements
- Images require authenticated fetch (cookies), downloaded v
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
lp", "feishu"], help="Force method")
parser.add_argument("--selector", help="Force CSS selector")
parser.add_argument("--urls-file", help="File with URLs (one per line)")
parser.add_argument("--audio-only", action="store_true", help="Extract audio only (video)")
parser.add_argument("--no-images", action="store_true", help="Skip image download (article)")
parser.add_argument("--cookies-browser", help="Browser for cookies (e.g., chrome, firefox)")
args = parser.parse_args()
urls = []
if args.urls_file:
with open(args.urls_file) as f:
urls = [line.strip() for line in f if line.strip() and not line.startswith("#")]
elif args.url:
urls = [args.url]
else:
parser.print_help()
sys.exit(1)
os.makedirs(args.output, exist_ok=True)
results = []
for url in urls:
r = route(url)
if args.method:
r["method"] = args.method
if args.selector:
r["selector"] = ar
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
titleHadHierarchicalSeparators = / [\\\/>»] /.test(curTitle);
curTitle = origTitle.replace(/(.*)[\|\-\\\/>»] .*/gi, "$1");
// If the resulting title is too short (3 words or fewer), remove
// the first part instead:
if (wordCount(curTitle) < 3)
curTitle = origTitle.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi, "$1");
The cookies-browser chrome pattern matches information-stealer behavior because it directs tooling to read authenticated cookies from the user's Chrome profile. In this skill context, that is especially sensitive: the agent is a web/video fetcher, so leveraging local browser credentials can enable access to private or premium content and normalize credential-adjacent data access beyond the expected scope.
- **Selector:** `.WB_text`
- **Method:** camoufox (recommended for reliable access)
- **Notes:** Some content requires login
## Bilibili (bilibili.com / b23.tv)
- **Method:** yt-dlp
- **Format selection:** `bestvideo[height<=N]+bestaudio/best[height<=N]`
- **Output:** Merged to MP4 via ffmpeg
- **Short links:** b23.tv redirects are handled by yt-dlp automatically
- **Premium content:** Use `--cookies-browser chrome` to pass login cookies
- **Audio extraction:** Use `--audio-only` flag for MP3 output
## YouTube (youtube.com / youtu.be)
- **Method:** yt-dlp
- **Notes:** Standard yt-dlp usage, no special handling
## Douyin (douyin.com)
- **Method:** yt-dlp
- **Notes:** May need cookies for some content
The README explicitly documents authenticated fetching and browser-cookie use, including Feishu authenticated image access, but does not warn users that the tool may access logged-in session data and private content. In a web-fetching skill, this increases the risk of unintentionally pulling sensitive account data or normalized developer acceptance of session-backed scraping without consent boundaries.
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.
## Adding New Platforms
1. Add entry to `ROUTE_TABLE` in `lib/router.py`
2. If needed, add image post-processing hook in `lib/article.py`
3. If needed, create dedicated handler in `lib/`
The skill advertises and documents capabilities that require network, filesystem, and shell access, but the manifest does not declare any explicit tool scope or permission boundaries. This increases the chance of overbroad execution in an agent environment and makes it harder for users or reviewers to understand what the skill is allowed to do.
The trigger phrases are broad enough to match many ordinary user requests, which can cause the skill to activate in contexts where users did not intend web fetching or downloading. In an agent system with network and file-write capability, over-triggering can lead to unnecessary external requests, data collection, or local file creation.
The skill explicitly documents use of authenticated browser cookies to access and download content, but it does not present a clear warning about privacy, account scope, or the sensitivity of browser-derived session data. This is dangerous because users may unknowingly authorize access to private or account-restricted content, and cookie-backed requests can expose personal data or violate least-privilege expectations.
The --cookies-browser option enables the tool to read authentication cookies from a local browser profile, but the interface gives no explicit warning that sensitive browser-stored session data will be accessed and then potentially used against arbitrary user-supplied URLs. In a web-fetching skill, this materially increases the risk of unintended authenticated requests, privacy exposure, or misuse of a logged-in session if users do not understand what the flag does.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
cmd_html += ["-s", selector]
print(f"[*] Scrapling GET: {url}")
r1 = subprocess.run(cmd_md, capture_output=True, text=True, timeout=60)
r2 = subprocess.run(cmd_html, capture_output=True, text=True, timeout=60)
md_text = _read_if_exists(md_file)
The manifest describes fetching and saving web articles/videos, which justifies network access and file writes. However, this implementation invokes external binaries via subprocess and uses a headless/anti-detection browser stack, adding execution capabilities that are not explicitly part of the stated purpose and are broader than ordinary fetching logic.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
print(f"[*] Scrapling GET: {url}")
r1 = subprocess.run(cmd_md, capture_output=True, text=True, timeout=60)
r2 = subprocess.run(cmd_html, capture_output=True, text=True, timeout=60)
md_text = _read_if_exists(md_file)
html_text = _read_if_exists(html_file)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
cmd_html += ["-s", selector]
print(f"[*] Scrapling fetch (browser): {url}")
r1 = subprocess.run(cmd_md, capture_output=True, text=True, timeout=120)
r2 = subprocess.run(cmd_html, capture_output=True, text=True, timeout=120)
md_text = _read_if_exists(md_file)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
print(f"[*] Scrapling fetch (browser): {url}")
r1 = subprocess.run(cmd_md, capture_output=True, text=True, timeout=120)
r2 = subprocess.run(cmd_html, capture_output=True, text=True, timeout=120)
md_text = _read_if_exists(md_file)
html_text = _read_if_exists(html_file)
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
return False
try:
__import__(name)
return True
except ImportError:
hint = hints.get(name, f"pip install {name}")
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
print(f"[*] Downloading: {url}")
print(f"[*] Command: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"[!] yt-dlp error:\n{result.stderr}")
The documentation explicitly instructs use of --cookies-browser chrome to reuse a local browser's authenticated Bilibili session for premium content. That expands the skill from ordinary public-content fetching into accessing account-scoped or paid content via local credentials, creating risk of unauthorized access and unintended exposure of sensitive browser session data.
The skill retrieves arbitrary remote content, follows through multiple network-fetch mechanisms including a browser engine, downloads images, and writes results to local storage with only status prints. In an agent setting, this can surprise users, enable unintended access to internal or sensitive URLs, and cause filesystem changes without clear consent or policy checks, making the context more dangerous than a standalone CLI utility.
Detected: suspicious.dynamic_code_execution