T08 · Insecure Dependencies
- Location
auto-download.js:317- Finding
Unpinned Dependency Is Installed and Executed at Runtime
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is mostly a Douban image downloader, but it can install an unpinned npm package at runtime and includes under-disclosed or mismatched behavior that users should review first.
Review before installing. Use only in an environment where it is acceptable for the skill to make Douban network requests, write downloaded images under your home directory, and install Playwright via npm. Prefer installing reviewed, pinned dependencies yourself first, and avoid passing arbitrary non-Douban URLs to download.js.
auto-download.js:317Unpinned Dependency Is Installed and Executed at Runtime
download.js:13User-Controlled Host Requests with Unrestricted Redirect Following
整体上,代码的大部分核心行为与声明相符:会根据名称搜索豆瓣内容、自动提取图片并批量下载到本地,且实现了已下载去重和延迟下载。也确实无需显式登录,使用无头浏览器完成页面访问。但存在两点实质性未声明能力:第一,搜索逻辑和照片提取逻辑明确支持 /celebrity/ 影人页面,能够下载影人照片,这超出了“电影/电视剧/综艺剧照和海报”的声明边界;第二,运行时会通过 child_process 执行 npm install playwright 自动安装依赖,这属于对本地环境的修改行为,描述中未提及。基于这些未声明能力,应判定为描述与实际行为存在不匹配。
该代码的核心功能是:给定一个具体的 photo 页面 URL,构造对应图片直链并下载到本地,同时通过 Referer 等请求头处理防盗链。这与声明中的高层目标存在明显差异。声明强调按片名搜索、批量抓取、支持缓存去重、反爬延迟、下载剧照和海报,且面向豆瓣内容;而实际代码没有任何搜索逻辑、没有批量循环、没有缓存或去重机制、没有延迟控制,也没有专门的海报处理流程。虽然“下载图片”这一大方向相关,但主要能力和使用方式都与描述不符,属于实质性描述-行为不匹配。
整体主功能与描述大体一致:代码确实面向豆瓣图片抓取下载,支持剧照/海报分类、自动搜索、去重缓存和随机延迟。但描述中的“完全自动化,不需要登录”与实际行为不符。代码在抓取失败时明确提示用户可能需要在浏览器中登录验证,甚至建议继承浏览器登录状态,这与“不需要登录”的关键承诺相冲突。此外,代码多处注释写明“需要根据实际平台进行适配”,说明其自动化能力并非描述中那样无条件、完整可靠。因此存在实质性描述与行为不一致。
The script automatically runs npm install playwright via execSync, which causes unreviewed code to be downloaded and executed at runtime. Package installation scripts can run arbitrary commands, so this expands the trust boundary from the skill itself to the package registry and local shell environment without explicit user consent.
The manifest describes a skill that accepts a movie/show title, automatically searches Douban, and batch-downloads posters/stills with cache deduplication and anti-scraping delay. This implementation instead requires a direct photo page URL as a CLI argument, extracts one photo ID, and downloads at most one primary image plus one fallback format; there is no search-by-title, batch logic, caching, or deduplication.
The trigger phrases are broad enough to match generic requests like '批量下载图片' or '获取海报', which could cause this skill to activate outside its intended Douban-only scope. Over-broad routing can lead an agent to invoke a web-crawling/download tool in inappropriate contexts, increasing the chance of unintended network access, policy violations, or user confusion.
The module doc comment states behavior involving reusing existing authenticated session state or attaching to an existing browser. In code, both Playwright entry points launch a new headless Chromium instance, and comments at L176 and L251 explicitly say not to connect to an existing browser, so the documentation contradicts actual behavior.
The manifest scope is limited to works such as movies, TV dramas, and variety shows. The code explicitly detects /celebrity/ search results and then navigates to celebrity photo pages, expanding behavior beyond content titles into person/celebrity image scraping.
Spawning a subprocess to install dependencies at runtime is a risky behavior because it changes the system state and executes external code without advance notice in the user-facing flow. Even when the command string is fixed, this can surprise users, bypass review processes, and expose the host to supply-chain or install-script abuse.
The header comment says the tool downloads variety/movie/TV stills and handles anti-hotlinking, implying support for that content class generally. In practice, the code only derives a fixed image URL pattern from a specific photo page URL and does not implement title lookup, category handling, or generalized still/poster discovery; the anti-hotlink handling is limited to setting a Referer header.
The HTTP request hard-codes Accept-Language: zh-CN,zh;q=0.9, which imposes a specific locale on all requests. The file does not offer user opt-in or explain that this is a region-specific requirement, so it conflicts with the language/locale policy criteria.
The request header forces Accept-Language: zh-CN,zh;q=0.9, which imposes a specific language/locale preference during network requests. Under the policy, locale constraints should be optional, user-selectable, or clearly justified as region-specific; this file provides neither.
The HTML-fetching logic also sets Accept-Language: zh-CN,zh;q=0.9, again forcing a specific locale for all users. This is a natural-language/locale policy issue because the skill does not provide a language choice or explain why all requests must prefer Chinese.
The manifest and header comment describe the skill as '完全自动化,不需要登录', but the user-facing guidance printed on failure tells users to open the site for login verification or use remote debugging to inherit browser login state. That is an active contradiction of the claimed no-login, fully automated workflow rather than a mere omitted detail.
The skill description, compatibility notes, and metadata are predominantly fixed to zh-CN usage, including metadata.language: zh-CN, without stating that this is the default or offering an opt-in language choice. Under the policy, forcing a specific language or locale without user choice can be a natural-language policy concern unless clearly justified.
The Accept-Language header is hard-coded to zh-CN,zh;q=0.9, which imposes a specific language/locale preference for requests regardless of user settings. This is a natural-language policy issue because the skill does not offer locale choice or explain why this locale is required.
The module doc comment explicitly states files are saved to 'output/{contentName}/{type}/', but the configured path actually writes under os.homedir()/.openclaw/output/photo-download. This is a direct documentation-to-code contradiction about where user data is stored.
Detected: suspicious.dangerous_exec