Back to skill

Security audit

小红书内容引擎

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Xiaohongshu content tool, but it needs review because it can send prompts and API keys to configurable services and persist learned content into its knowledge files.

Install only if you are comfortable with this skill calling third-party crawler, LLM, image, and video APIs. Use provider keys dedicated to this skill, avoid project-local `.env` files from untrusted workspaces, do not set custom base URLs unless you control them, prefer `--no-real-video` until you intentionally approve costs, and review graph changes before reusing them as trusted brand context.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/content_engine/llm.py:52
Finding

OpenRouter API credentials are transmitted to the Ofox endpoint

Content
View full analysis
str | None: """Load credentials from environment variables or supported configuration files.""" for var in ("OFOX_API_KEY", "OPENROUTER_API_KEY"): if v := os.environ.get(var): return v.strip() for path_fn in _TOKEN_SEARCH_PATHS: try: path = path_fn() except Exception: continue if not path.exists() or not path.is_file(): continue try: for line in path.read_text(encoding="utf-8").splitlines(): line = line.strip() for var in ("OFOX_API_KEY", "OPENROUTER_API_KEY"): if line.startswith(f"{var}="): val = line.split("=", 1)[1].strip() return val.strip('"').strip("'") except (OSError, UnicodeDecodeError): continue return None ``` ```python self.api_key = api_key or _load_ofox_key() if not self.api_key: raise OfoxError(_help_message()) self.base_url = ( base_url or os.environ.get("OFOX_BASE_URL") or OFOX_BASE_URL ).rstrip("/") ``` ```python req = urllib.request.Request( url, data=body, headers={ "Content-Type": "application/json; charset=utf-8", "Authorization": f"Bearer {self.api_key}", }, method="POST", ) with urllib.request.urlopen(req, timeout=self.timeout) as resp: data = json.loads(resp.read()) ``` The default value of `OFOX_BASE_URL` is `https://api.ofox.ai`. The behavior is also explicitly covered by `tests/test_llm.py:43-46`, which verifies that `OPENROUTER_API_KEY` is accepted as a fallback Ofox key. ### Technical Analysis Credential selection and provider endpoint selection are not coupled. If `OFOX_API_KEY` is absent but `OPENROUTER ...[truncated 1488 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/content_engine/client.py:40
Finding

API credentials and confidential prompts can be redirected to arbitrary endpoints

Content
View full analysis
dict[str, str]: headers = { "Accept": "application/json", "User-Agent": self.user_agent, } if self.token: scheme = self.auth_scheme.strip() value = ( self.token if not scheme or scheme.lower() == "raw" else f"{scheme} {self.token}" ) headers[self.auth_header] = value return headers ``` ```python req = urllib.request.Request( url, data=data, headers=headers, method=method, ) with urllib.request.urlopen(req, timeout=self.timeout) as resp: body = resp.read().decode("utf-8") return json.loads(body) ``` The other provider clients similarly accept unrestricted environment-controlled base URLs: ```python self.base_url = ( base_url or os.environ.get("OFOX_BASE_URL") or OFOX_BASE_URL ).rstrip("/") ``` ```python base_url = ( base_url or os.environ.get("ARK_BASE_URL") or ARK_BASE_URL ).rstrip("/") ``` ### Technical Analysis The crawler, Ofox, and Ark clients send reusable credentials to configurable base URLs without enforcing HTTPS or validating the destination hostname. The crawler configuration loader also reads endpoint overrides from `.env` in the current working directory. This creates a dangerous trus ...[truncated 1975 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/content_engine/images.py:16
Finding

Untrusted media URLs permit server-side request forgery from the Agent environment

Content
View full analysis
list[Path]: outdir.mkdir(parents=True, exist_ok=True) saved: dict[int, Path] = {} with ThreadPoolExecutor(max_workers=max_workers) as ex: futures = { ex.submit(_download_one, url, outdir, idx, timeout, max_bytes): idx for idx, url in enumerate(urls, start=1) } ``` ```python def _download_one( url: str, outdir: Path, idx: int, timeout: int, max_bytes: int, ) -> Path | None: ext = _guess_extension(url) dest = outdir / f"image_{idx:03d}.{ext}" written = 0 try: with urllib.request.urlopen(url, timeout=timeout) as resp, dest.open("wb") as f: while True: chunk = resp.read(64 * 1024) if not chunk: break written += len(chunk) if written > max_bytes: f.close() dest.unlink(missing_ok=True) raise RuntimeError( f"exceeded {max_bytes // (1024*1024)} MB" ) f.write(chunk) return dest ``` The extraction workflow passes URLs obtained from the crawler response directly into these download functions: ```python if note.type == "video" and note.video_url and not args.no_video: download_video(note.video_url, video_path) ``` ```python elif note.type == "normal" and note.image_urls and not args.no_images: saved = download_images(not ...[truncated 2432 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Warning
Location
SKILL.md:84
Finding

Remote content can be written into persistent Agent context without approval

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:610
Finding

Installation instructions execute an unpinned package directly from the registry

Content
View full analysis
Remediation
View remediation
install ``` 2. Publish and verify the expected package integrity hash. 3. Remove `-y` so users receive an execution confirmation. 4. Document the expected publisher, registry, package version, and release provenance. 5. Review the package's lifecycle scripts and dependency tree before recommending it. 6. Prefer a lockfile-backed installation process for reproducible dependency resolution. 7. Advise users to run optional installation in a restricted environment without unrelated secrets. 8. Update the pinned version only after a security review. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (119)

Tainted flow: 'req' from os.environ.get (line 69, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The request target is derived from a configurable base_url that can come from the OFOX_BASE_URL environment variable, and the function sends both the bearer token and full prompt to that endpoint. If an attacker can influence environment configuration, they can redirect requests to an attacker-controlled server, causing credential exfiltration and leakage of potentially sensitive brand/product prompt data; this is effectively SSRF plus secret disclosure rather than a harmless configuration feature.

Content

Scanner excerpt · scripts/content_engine/nano_banana.py (reported line 80)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            data = json.loads(resp.read())
    except urllib.error.HTTPError as e:
        err_body = e.read().decode("utf-8", errors="replace")[:500]

Tainted flow: 'req' from os.environ.get (line 186, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/content_engine/seedance.py (reported line 156)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            data = json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")[:500]

Tainted flow: 'req' from os.environ.get (line 186, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/content_engine/seedance.py (reported line 193)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            data = json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body = e.read().decode("utf-8", errors="replace")[:500]

Tainted flow: 'req' from os.environ.get (line 186, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The code downloads an arbitrary URL returned in the task response without validating the scheme, host, size, or content type. If the upstream API, task metadata, or network path is compromised, this can turn the client into an SSRF-like fetcher or cause it to retrieve attacker-controlled content to a chosen local path, which is more dangerous in an automation skill that handles external content and saves files automatically.

Content

Scanner excerpt · scripts/content_engine/seedance.py (reported line 254)May include surrounding context.

python
out_path.parent.mkdir(parents=True, exist_ok=True)
    try:
        req = urllib.request.Request(url, headers={"User-Agent": "curl/8.7.1"})
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            out_path.write_bytes(resp.read())
    except urllib.error.HTTPError as e:
        raise SeedanceError(f"HTTP {e.code} downloading video from {url[:80]}") from e

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

There is a material description-to-code mismatch. The description presents a higher-level product with two modes, especially an analysis mode producing a specific 18-dimensional breakdown card and a generation mode using LLM and image systems plus a shared knowledge graph. The code shown, however, is only an initializer for a toolkit package and documents lower-level extraction utilities: crawler client integration, parsers, link resolution, media download/extraction, and preflight checks. Some of these actual capabilities—especially downloading mp4/images and performing ffmpeg/environment/token/network checks—are undeclared in the description. Meanwhile, the prominent declared generation and knowledge-graph behaviors are not supported by this code chunk. While some overlap exists around XHS content analysis, the actual code is substantially narrower in some respects and includes additional operational capabilities not described.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a higher-level content-analysis/generation engine with structured breakdown, brand-aware creative generation, knowledge graph maintenance, and future video/multi-platform features. This code chunk does not implement any of those core behaviors. Instead, it is a low-level crawler client focused on network access to external APIs for note/comment retrieval. While such crawling could be a supporting component for a broader content engine, the supplied description does not mention this concrete capability, external service, or local token/config file access. Therefore the code's actual behavior is materially narrower and different from the declared primary purpose, and it includes undeclared resource access patterns.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description presents a broad content-engine skill with analytical decomposition, generative production, shared knowledge graph behavior, and future multimodal/platform extensions. The supplied code chunk, however, is a narrow parser module whose sole responsibility is converting raw Xiaohongshu API responses into dataclasses for notes and comments. While this parser could be a supporting component of such a larger system, the code itself does not implement the core declared behaviors. In particular, it explicitly excludes comment semantic classification and contains no LLM calls, no generation pipeline, no graph logic, and no mode orchestration. Therefore, the code chunk's actual behavior is materially narrower than the declared purpose, creating a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents an end-user skill for Xiaohongshu content decomposition and generation, with shared knowledge graph behavior. The supplied code chunk instead contains only tests for low-level LLM configuration and client setup. While Ofox is mentioned in both, the actual code does not perform the advertised analysis/generation functions, consume XHS links, manage graph knowledge, or produce content assets. This is a materially different purpose rather than a mere supporting detail, so the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The supplied code does not implement the declared core behaviors of the skill such as taking a Xiaohongshu link, producing an 18-dimension structured deconstruction, invoking Ofox/LLM/Nano Banana to generate scripts/assets, maintaining a knowledge graph, or planning video generation. Instead, it tests local helper functions for parsing note IDs, searching markdown files/directories, creating storage paths, and writing fallback stub cards. These behaviors may support a broader content engine, but this code chunk’s actual purpose is materially narrower and different: lookup/storage utilities and their tests. Therefore the description does not accurately represent what this specific code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The supplied code is a test module for parser behavior. Its actual purpose is to verify helper functions like parse_note, parse_comments, hashtag cleaning, integer coercion, image/video URL extraction, and pinned-comment heuristics for Xiaohongshu note/comment payloads. While this is related to the Xiaohongshu domain, it is only a narrow ingestion/parsing support layer. The declared description presents a much broader product: a two-mode content engine for structured viral-post decomposition and AI-powered content generation with a shared knowledge graph. None of those core capabilities appear in this code chunk. Because the code’s primary behavior is materially narrower and different from the declared main functionality, this is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description focuses on a Xiaohongshu content engine for analyzing viral posts, generating scripts/copy/images/covers/tags from decomposition cards, and maintaining a shared knowledge graph. The supplied code does not implement or test any of those capabilities. Instead, it is specifically a test file for a Seedance video task API wrapper: submit a prompt, query/poll task state, extract a generated video URL, download the resulting MP4, and estimate video-generation cost. While the description mentions future video generation planning in v2.1, this code is narrowly about Seedance API task handling and video download, not the declared primary modes or graph functionality. Therefore the code chunk's actual behavior is materially different from the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description presents a content analysis and generation engine as the core functionality. In contrast, the provided code chunk only contains tests for validation utilities that perform QA on already-generated assets and workspace structure. While validation could be a supporting part of such a system, the code shown does not implement the declared primary behaviors (XHS link breakdown, asset generation, or graph-based intelligence) and instead focuses on a separate validator/reporting subsystem. This is a material description-behavior mismatch for the supplied chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a broad Xiaohongshu content engine centered on two major modes: analysis of XHS viral links and generation of branded assets, with a shared graph and future multi-platform expansion. The supplied code, however, is narrowly focused on testing a video composition module. It validates markdown shot parsing, mocked Seedance task submission, partial failure handling, report generation, and ffmpeg concatenation checks. While Seedance video generation is mentioned in the description as a future/planned capability (v2.1), this code does not implement or demonstrate the declared primary functions of the skill. Therefore the actual behavior of this chunk is materially narrower and different from the declared purpose, indicating a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. 找到 skill 根目录(`SKILL.md` 所在目录)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
88% confidence
Finding

The --no-confirm option weakens the guardrail around external paid API invocation, allowing an agent or wrapper to suppress user confirmation for network actions that incur cost and generate artifacts. In a skill that already has shell, network, and file-write capabilities, removing confirmation materially increases the chance of abuse, surprise charges, or unintended bulk actions.

Content

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

md
- 顺序提交到火山方舟 Seedance 2.0(异步任务 + 轮询,单 shot 通常 1-3 分钟)
- 失败的 shot 不阻断其他 shot,只在 `partial-video.md` 里写明哪几个失败 + 失败 shot 的 prompt 方便手补
- 成功的 shot 用 ffmpeg concat 拼成 `final-video.mp4`
- 开关:`--no-real-video`(仅出 prompt 不调 API)/ `--async`(仅提交不等结果)/ `--no-confirm`(跳过 3 秒倒数)

### Step 8:质检 validator(v0.2.1 起内置)
- **硬错** → 自动重跑相应步骤(最多 1 次):禁忌词命中 / 文件为空 / tags < 5 / 图片过小(疑似生成失败)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

md
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

md
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

md
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

md
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · references/configuration.md (reported line 29)May include surrounding context.

md
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · references/configuration.md (reported line 59)May include surrounding context.

md
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/content_engine/client.py (reported line 6)May include surrounding context.

python
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/content_engine/client.py (reported line 48)May include surrounding context.

python
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/content_engine/client.py (reported line 156)May include surrounding context.

python
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/content_engine/llm.py (reported line 8)May include surrounding context.

python
设计原则:
- 默认走 https://agent.delu.cn 的爬虫接口
- 不把具体接口细节写死:base URL、endpoint path、认证 header、请求方法都可用 env 覆盖
- token 多源解析:env > XDG config > 项目 .env
- 无 token 时允许无认证请求,兼容内网 / IP allowlist 场景
"""