Back to skill

Security audit

谛听.skill

Security checks for vulnerabilities and agentic risk

Overview

This digest skill is mostly coherent, but its helper can persist scheduled jobs and fetch unvalidated operator-supplied URLs, so it should be reviewed before installation.

Install only if you trust the feed provider and operator. Before enabling recurring delivery, inspect the dry-run cron payload, use explicit delivery targets, avoid untrusted feed URL overrides, and do not store secrets in the local prompt or profile files.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T01 · Skill Instruction Hijacking

Warning
Location
scripts/follow_scoutx.py:1640
Finding

Indirect Prompt Injection Through Untrusted Feed Content

Content
View full analysis
dict[str, Any]: source_values = raw.get("sources") or [] sources = [str(value).strip() for value in source_values if str(value).strip()] return { "content_id": str(raw.get("content_id") or raw.get("id") or raw.get("url") or "").strip(), "source_type": "scoutx", "source_label": SOURCE_TYPE_LABELS["scoutx"], "title": html.unescape(str(raw.get("title") or "").strip()), "summary": str(raw.get("summary") or raw.get("summary_text") or raw.get("description") or raw.get("content") or "").strip(), "url": str(raw.get("url") or raw.get("canonical_url") or "").strip(), "published_at": str(raw.get("published_at") or raw.get("publishedAt") or "").strip(), "sources": sources or [SOURCE_TYPE_LABELS["scoutx"]], "tags": [str(value).strip() for value in raw.get("tags") or [] if str(value).strip()], "metadata": {}, } ``` The externally supplied title and summary are then copied into the LLM payload: ```python def payload_item(item: dict[str, Any]) -> dict[str, Any]: return { "content_id": item["content_id"], "source_type": item.get("source_type", "scoutx"), "source_label": item.get("source_label", SOURCE_TYPE_LABELS["scoutx"]), "title": item["title"], "summary_text": compress_item_summary(item, char_budget=per_item_budget), "canonical_url": item["url"], "published_at": item["published_at"], "sources": item["sources"], "tags": item["tags"], "metadata": item.ge ...[truncated 5473 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/follow_scoutx.py:296
Finding

Insufficient Feed URL Validation Allows Internal Network and Arbitrary-Scheme Access

Content
View full analysis
bool: if not url: return True parsed = urllib.parse.urlparse(url) host = (parsed.netloc or "").lower() return host.endswith(".example.com") or host == "example.com" def ensure_real_feed_url(url: str | None) -> str: if is_placeholder_feed_url(url): raise SystemExit( "Follow ScoutX operator setup incomplete: the bundled feed URL is still a placeholder. " "Update the distributed skill package's service.json or run configure-service on this installation. " "Normal end users should not be asked to provide a feed URL." ) return str(url) ``` The resulting value is passed directly to `urllib.request.urlopen()`: ```python service_config = load_service_config() env_var = SOURCE_TYPE_ENV_VARS.get(source_type, "FOLLOW_SCOUTX_FEED_URL") target_url = feed_url or os.getenv(env_var, service_feed_url(service_config, source_type)) target_url = ensure_real_feed_url(target_url) timeout = int( os.getenv( "FOLLOW_SCOUTX_TIMEOUT_SECONDS", str(service_config.get("timeout_seconds") or DEFAULT_TIMEOUT_SECONDS), ) ) request = urllib.request.Request( url=target_url, headers={ "Accept": "application/json", "User-Agent": os.getenv("FOLLOW_SCOUTX_USER_AGENT", DEFAULT_USER_AGENT), }, method="GET", ) try: with urllib.request.urlopen(request, timeout=timeout) as response: raw = response.read().decode("utf-8") except urllib.error.HTTPError as exc: body = exc.read().decode("utf-8", errors="replace") raise SystemExit(f"HTTP {exc.code} {exc.re ...[truncated 3971 chars]
Remediation
View remediation
Vulnerability Patterns
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (49)

Tainted flow: 'request' from os.getenv (line 1036, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The skill allows feed URLs to be overridden from environment variables and then performs outbound requests to those URLs. In a hostile or multi-tenant runtime, this creates an SSRF-like capability that can be abused to reach attacker-chosen internal or sensitive network endpoints, especially because the fetched response is then parsed and surfaced by the tool.

Content

Scanner excerpt · scripts/follow_scoutx.py (reported line 1046)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(request, timeout=timeout) as response:
            raw = response.read().decode("utf-8")
    except urllib.error.HTTPError as exc:
        body = exc.read().decode("utf-8", errors="replace")

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents the skill as a lightweight digest/setup experience, but the body includes persistent local storage, prompt file synchronization, external network retrieval, and installation/removal of OpenClaw cron jobs. This mismatch is dangerous because it conceals materially more powerful behavior than users and reviewers would infer from the metadata, increasing the risk of unnoticed persistence and unintended system changes.

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 100)May include surrounding context.

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/follow_scoutx.py configure

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/follow_scoutx.py (reported line 249)May include surrounding context.

python
def prompt_backups_dir() -> Path:
    return prompts_dir() / "backups"


def bundled_prompts_dir() -> Path:

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
95% confidence
Finding

The skill reads bundled/local prompt files and includes them verbatim in the JSON emitted by prepare-digest via the prompts field. That exposes internal system prompts/instructions to downstream consumers and any caller able to run the command, weakening prompt confidentiality and making it easier to manipulate or subvert later LLM behavior.

Content

Scanner excerpt · scripts/follow_scoutx.py (reported line 507)May include surrounding context.

python
for key, filename in mapping.items():
        prompt_path = prompts_dir() / filename
        prompts[key] = prompt_path.read_text(encoding="utf-8").strip()
    return prompts


def split_csv(value: str | None) -> list[str] | None:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The file states in Chinese that it is for coding agents working in this repository, and the operational instructions throughout the file are written only in Chinese. This creates a language/locale constraint for operators of the skill without any explicit opt-in or alternative language option, which matches the policy category for forced language use.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The example configuration sets --language zh-CN, and the documented profile structure later hard-codes "language": "zh-CN" as the preference value. In a natural-language guidance file, this can amount to a locale policy issue because it normalizes a specific language choice without stating that users may choose their own language or that this is just an example.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.