T09 · Insecure Skill Coding Practices
- Location
lib/article.py:245- Finding
Unrestricted image retrieval permits SSRF and local file disclosure
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill mostly does what it claims, but it can fetch arbitrary URLs, save content locally, use logged-in browser sessions, and has weak scoping around those sensitive actions.
Install only if you are comfortable with a skill that can fetch arbitrary web content, run third-party scraping/downloading tools, write persistent archives, and sometimes use your logged-in browser context. Use it with explicit URLs only, avoid cookie-based or private-document modes unless necessary, choose an output directory carefully, and prefer pinned dependencies or an isolated environment.
lib/article.py:245Unrestricted image retrieval permits SSRF and local file disclosure
SKILL.md:115Unpinned dependencies and unverified runtime component downloads create supply-chain exposure
这段代码的核心用途非常明确:它是 Mozilla/Arc90 风格的 Readability 内容抽取实现,用于从现有网页 DOM 中识别并清洗出“可读文章正文”。代码包含标题提取、byline/metadata 识别、清理 script/style/iframe/form、处理懒加载图片、修正相对链接、正文候选评分等典型阅读模式逻辑。它并不包含与声明中多项关键能力相对应的实现:没有 HTTP 请求、没有 URL 获取、没有视频流解析与下载、没有保存/归档接口、没有摘要分析模型调用。因此,声明描述明显超出了该代码块实际行为;虽然“网页阅读/文章提取”部分方向相关,但对下载、归档、分析、摘要等主能力存在实质性不匹配。
The YARA hit is not proof of malware, but the documented --cookies-browser behavior matches a known sensitive pattern: importing browser cookies so requests run with the user's authenticated sessions. In this skill's context, that can expose private account data and resembles credential/session misuse even if the stated goal is content retrieval rather than theft.
-o, --output DIR 输出目录(默认: 当前目录) -q, --quality N 视频质量(默认: 1080) --method METHOD 强制方法: scrapling, camoufox, ytdlp, feishu --selector CSS 强制 CSS 选择器 --urls-file FILE URL 列表文件(每行一个,# 注释) --audio-only 仅提取音频 --no-images 跳过图片下载 --cookies-browser NAME 浏览器 cookies(如 chrome, firefox) --category NAME 归档子目录名 --json-output JSON 格式输出(程序化调用)
## 配置
创建 `~/.claude/web-reader.json` 配置归档目录:
```json
{
"archive_dir": "~/Documents/docs/articles",
"categories": ["技术", "产品", "行业"]
}
data-src 属性 + mmbiz.qpic.cn<img> 是 SVG 懒加载占位符Referer: https://mp.weixin.qq.com/ 请求头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)")
parser.add_argument("--category", help="Archive category subfolder name")
parser.add_argument("--json-output", action="store_true", help="Output result as JSON (for programmatic use)")
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)
output_dir = args.output
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");
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
- **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 content is presented in Chinese and says 'for Claude Code' without offering any language or locale choice. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.
The skill clearly instructs file reads/writes, shell execution, and network access, yet it declares no explicit tool scope or permission boundaries. That increases the chance of over-privileged execution and makes it harder for users or the platform to understand that local files, browsers, and remote sites may be accessed.
The trigger list includes broad terms like '摘要' and '总结文章', which could accidentally invoke the skill in unrelated conversations. Because this skill can write files, access the network, and potentially use authenticated browser context, unintended activation materially raises the risk of surprising or unauthorized actions.
The skill automatically downloads and archives content to local directories but does not prominently warn users that files will be written to disk, including under configured paths outside the current workspace. This can lead to unanticipated persistence of potentially sensitive or copyrighted material and increases the risk of silent local data sprawl.
The skill instructs use of browser cookies to access authenticated content, which can expose session data and cause the agent to act with the user's logged-in privileges. In a web-reading/archive context, this materially expands access into private accounts and subscription-gated content without strong justification or consent boundaries.
The documentation describes using browser cookies and authenticated browser contexts but does not give a clear privacy warning that the agent may access user-only or enterprise-restricted content under the user's identity. In context, that omission is dangerous because the skill is framed as a general web reader, which understates the sensitivity of these actions.
In-browser authenticated fetches with credentials include the user's session context and allow access to private Feishu content and media. That creates meaningful privacy and data-exposure risk because the agent could retrieve, save, or process restricted enterprise documents beyond what users expect from a generic web reader.
The code silently escalates to headless browser fetching and then anti-detection tooling when simpler retrieval fails, without any explicit warning in this path. That makes the behavior more dangerous in this skill context because arbitrary links can trigger heavier browser automation and network access than a user might reasonably expect from a 'web reader'.
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 skill invokes external CLI tools and escalates from normal HTTP fetching to headless and anti-detection browser automation against user-supplied URLs. In context, this broadens the skill from passive reading into a network-capable automation tool that could access internal services, bypass some site defenses, or perform higher-impact retrieval without clear restrictions.
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 Feishu guidance explicitly recommends fetching image resources with the page's authenticated session via credentials: 'include', which extends the skill from public web reading into access using a logged-in user's cookies. In a link-fetching skill, this increases the chance of retrieving private tenant content or causing the agent to act on behalf of the user without an explicit consent boundary.
The Feishu section describes downloading images with included credentials but omits any warning that authenticated enterprise content may be accessed through the current session. That is risky because users may expect simple page scraping, not session-backed retrieval of potentially private documents and media.
The Bilibili documentation instructs use of --cookies-browser chrome to pull browser login cookies for premium content, which goes beyond the stated read/download purpose and touches sensitive local credential material. Even if intended for convenience, this creates a pathway for the skill to access subscription-gated content using the user's existing authenticated session.
The file documents use of browser cookies for premium-content access but provides no warning that this leverages a logged-in account and may expose account, privacy, and policy risks. In practice, users may not realize the skill could read local browser session state to retrieve restricted media.
This markdown file describes saving articles, images, and videos to local directories and automatically archiving them, which can affect user storage and filesystem contents. The usage examples show output paths, but there is no explicit warning or disclosure about overwriting, storing downloaded content locally, or archive side effects.
Detected: suspicious.dynamic_code_execution