Back to skill

Security audit

Truth Seeking Fact Check

Security checks for vulnerabilities and agentic risk

Overview

This fact-checking skill is mostly coherent, but its privacy and verification claims are materially stronger than what the code actually enforces.

Review before installing if you may check private or sensitive text. Use only with external data sources disabled unless you accept sending search queries to Brave, do not rely on the blockchain verification as strong proof, and prefer pinned dependencies plus narrower permissions before production use.

Vulnerability Patterns
  • 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
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
checker.py:197
Finding
Undisclosed Transmission of User Content to Brave Search## Vulnerability Details **File Location**: `checker.py:197-200`, `datasource.py:42-52`, `SKILL.md:23-30` **Vulnerability Type**: Privacy violation and undisclosed external data transmission **Risk Level**: High ### Vulnerable Code ```python # checker.py:197-200 def _check_sentence(self, sentence: str, position: int, result: CheckResult, explain: ConfidenceExplain): """Single-sentence check""" # Data source search search_results = self.datasource.get_search_results(sentence) ``` ```python # datasource.py:42-52 headers = { "Accept": "application/json", "X-Subscription-Token": self.api_key } params = { "q": query, "count": self.count } try: resp = requests.get(self.base_url, headers=headers, params=params, timeout=5) ``` The documentation claims that submitted content is processed locally and is not uploaded to external servers. However, when the Brave data source is configured, every sentence is passed directly to `get_search_results()` and included in the `q` query parameter of an HTTPS request to `api.search.brave.com`. ### Technical Analysis This creates a material discrepancy between the documented privacy model and actual runtime behavior. Complete user sentences may contain personal information, confidential business data, credentials, unpublished claims, or other sensitive material. Query parameters can also be recorded by the remote provider and network infrastructure involved in processing the request. Although Brave integration requires configuration containing an API key, the code does not request per-query consent, display a transmission warning, redact sensitive information, or minimize the submitted query. ### Attack Path 1. A user relies on the Skill's statement that submitted content never leaves the local environment. 2. The user or administrator enables the Brave data source and supplies an API key. 3. The user submits confidential text for ...[truncated 711 chars]
Remediation
## Remediation Suggestions 1. Correct `SKILL.md`, package metadata, and `get_metadata()` so they explicitly disclose that configured external data sources receive search queries. 2. Keep remote data sources disabled by default. 3. Require explicit, informed consent before transmitting each document or batch. 4. Display the destination domain and the exact data category that will be transmitted. 5. Minimize queries by extracting non-sensitive keywords locally instead of sending complete sentences. 6. Add optional local redaction for email addresses, credentials, identifiers, and other sensitive patterns. 7. Provide a strictly offline mode that prevents all outbound requests. 8. Add integration tests confirming that no network request occurs unless external search has been explicitly enabled.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
manifest.json:8
Finding
Overbroad File-Read Permission Violates Least Privilege## Vulnerability Details **File Location**: `manifest.json:8`, `package.json:12`, `openclaw.plugin.json:13`, `compliance.py:21-26` **Vulnerability Type**: Excessive permission declaration **Risk Level**: Medium ### Vulnerable Configuration and Code ```json "permissions": ["content_verify", "file_read"] ``` ```python # compliance.py:21-26 dict_path = os.path.join(os.path.dirname(__file__), 'sensitive_words.txt') if os.path.exists(dict_path): with open(dict_path, 'r', encoding='utf-8') as f: for line in f: word = line.strip() if word: sensitive_words.append(word) ``` ### Technical Analysis The Skill requests a generic `file_read` permission, while the reviewed implementation only attempts to read one package-local file, `sensitive_words.txt`. A platform-wide file-read capability is broader than required for that operation. The current code does not contain a path traversal or arbitrary-file-read endpoint. Nevertheless, granting an unnecessarily broad permission increases the authority available to the Skill and violates least-privilege design. If the Skill, one of its dependencies, or a future update is compromised, the existing permission could facilitate access to unrelated host files. ### Attack Path 1. The Skill is installed with generic file-read permission. 2. A future malicious update, compromised dependency, or exploitable code path executes within the Skill's permission context. 3. The malicious code uses the already granted file-read capability to inspect files unrelated to fact checking. 4. Accessible configuration files, local application data, or secrets may be collected within the limits imposed by the host platform. This is a privilege-exposure path rather than evidence that the current implementation already reads arbitrary files. ### Impact Assessment The obtainable scope depends on how OpenClaw defines and enforces `file_read`. I ...[truncated 279 chars]
Remediation
## Remediation Suggestions 1. Remove the generic `file_read` permission if package-local resources can be accessed without it. 2. Embed the small default dictionary directly in the package or load it through a restricted package-resource API. 3. If a permission is necessary, request a capability limited to the exact immutable package resource. 4. Document why each permission is required. 5. Add permission regression checks that reject future manifests introducing capabilities not exercised by the implementation.

T08 · Insecure Dependencies

Warning
Location
requirements.txt:4
Finding
Open-Ended and Unused Third-Party Dependencies Expand Supply-Chain Risk## Vulnerability Details **File Location**: `requirements.txt:4-7` **Vulnerability Type**: Non-reproducible dependency resolution and unnecessary dependency exposure **Risk Level**: Medium ### Vulnerable Configuration ```text requests>=2.31.0 beautifulsoup4>=4.12.0 lxml>=5.1.0 nltk>=3.8.1 ``` ### Technical Analysis All dependencies use open-ended lower bounds. Consequently, an installation may resolve to any future version satisfying the minimum, making builds non-reproducible and allowing unreviewed dependency changes to enter the runtime environment without a corresponding project update. Of the listed packages, only `requests` is imported by the reviewed source. `beautifulsoup4`, `lxml`, and `nltk` are not used by the current implementation. Installing unnecessary libraries increases the number of packages and transitive dependencies that must remain trustworthy and patched. No malicious or typosquatted package was identified in the declared list. The issue is the avoidable supply-chain exposure created by unbounded and unused dependencies. ### Attack Path 1. An administrator installs the Skill at a later date. 2. The package resolver selects the latest versions allowed by the open-ended constraints. 3. A selected package or transitive dependency contains a newly introduced vulnerability, malicious release, or incompatible behavior. 4. The affected dependency code is installed into the Skill environment. 5. If imported or activated, that code executes with the permissions of the Skill process. ### Impact Assessment Potential impact depends on the behavior of a compromised or vulnerable dependency. At maximum, dependency code could access process data, perform network operations, or use permissions available to the Skill. The current repository does not establish that such compromise has already occurred, but its dependency policy unnecessarily enlarges the exposure.
Remediation
## Remediation Suggestions 1. Remove `beautifulsoup4`, `lxml`, and `nltk` unless concrete runtime functionality requires them. 2. Pin required packages to exact, reviewed versions. 3. Generate a locked dependency file containing cryptographic hashes. 4. Review and pin transitive dependencies where the deployment process permits it. 5. Use automated vulnerability and license scanning in the release pipeline. 6. Rebuild and retest deliberately when dependency versions are updated rather than accepting arbitrary future releases.

T09 · Insecure Skill Coding Practices

Note
Location
formatter.py:76
Finding
Type-Handling Defects Cause Markdown and Scheduled Checks to Fail## Vulnerability Details **File Location**: `formatter.py:76-79`, `scheduler.py:100-102`, `main.py:73` **Vulnerability Type**: Unhandled type mismatch and availability failure **Risk Level**: Low ### Vulnerable Code ```python # formatter.py:76-79 if result.problematic_sentences: md += f"## Possible problematic sentences\n" for i, item in enumerate(result.problematic_sentences, 1): md += f"### {i}. Position {item['position'] + 1}\n" md += f"- Sentence: {item['sentence']}\n" ``` `result.problematic_sentences` contains `ProblemItem` objects, but the formatter accesses each object as if it were a dictionary. ```python # scheduler.py:100-102 result = self.skill.check_text(task.text, output_format="json") current_score = result.get('credibility_score', 0) # Update the last check time task.last_check = current_time ``` ```python # main.py:73 return self.formatter.format_result(result, output_format) ``` When `output_format` is `json`, `format_result()` returns a serialized string. The scheduler then calls `.get()` on that string. ### Technical Analysis Both defects are deterministic type mismatches: - Markdown rendering fails whenever the result contains at least one `ProblemItem`, because objects of that class do not support dictionary subscripting. - Scheduled checking fails after every successful JSON-formatted check because Python strings do not provide a dictionary-style `.get()` method. The scheduler catches the resulting exception and logs it, but does not produce a successful scheduled result. Because `last_check` is assigned after the failing `.get()` call, it is not updated, making the task eligible to fail again during the next scheduler loop. ### Attack Path **Markdown path:** 1. A user submits content that produces a low source-match result. 2. The checker adds a `ProblemItem` to `problematic_sentences`. 3. The caller requests Markdown output. 4. `_ ...[truncated 857 chars]
Remediation
## Remediation Suggestions 1. Access `ProblemItem` attributes directly: ```python md += f"### {i}. Position {item.position + 1}\n" md += f"- Sentence: {item.sentence}\n" md += f"- Reason: {item.reason}\n" md += f"- Credibility: {item.score:.1f}/10\n" ``` 2. Have the scheduler request dictionary output instead of JSON, or deserialize the returned JSON before accessing fields: ```python result_json = self.skill.check_text(task.text, output_format="json") result = json.loads(result_json) current_score = result.get("credibility_score", 0) ``` 3. Update `last_check` in a defined failure-handling path to prevent immediate repeated retries. 4. Add unit tests for Markdown output containing one or more problem items. 5. Add integration tests covering the first and subsequent scheduled executions. 6. Use static type checking to detect object-versus-dictionary and string-versus-dictionary mismatches.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (26)

Intent-Code Divergence

High
Confidence
98% confidence
Finding
This is a true vulnerability because the code claims to verify blockchain evidence, but it never queries on-chain data or a trusted API. Instead, it extracts a hex string from the user-supplied URL and treats a 10-character prefix match against the locally computed hash as proof, which can be trivially spoofed by crafting a URL whose path begins with the target hash prefix. In a trust or evidence-validation workflow, this can produce false 'verified' results and undermine integrity guarantees.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file presents all user-facing changelog content in Chinese, including headings and feature descriptions, with no indication that another language is available or that the skill is intentionally restricted to a Chinese-speaking or region-specific audience. Under the policy rule for language/locale constraints, this is a natural-language policy violation because it imposes a specific language without opt-in or justification.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill markets itself as providing '100% privacy protection' and 'fully local/offline' processing, but the same section admits model API calls may occur. That creates a materially misleading privacy claim: users may submit sensitive text believing it never leaves their environment, when in practice content can be transmitted to an external model provider depending on configuration.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The module name and all user-facing descriptions/docstrings are written in Chinese, with no indication that other languages are supported or that Chinese is an opt-in choice. This creates a natural-language policy concern if the broader environment expects language neutrality or user choice.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code’s top-level description and user-facing strings are written exclusively in Chinese, indicating the skill is designed to operate in a fixed language/locale. The file contains no mechanism offering users a language choice or documenting a justified region-specific constraint, which matches the language/locale policy violation criteria.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The module docstring and scoring model define "常识符合度" as one of the core fact-checking dimensions, and `_check_common_sense` claims to perform that check. However, the main `check()` flow never calls `_check_common_sense`, so this advertised dimension remains at its default initialized score instead of being assessed from the input text.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The module name, description, and class docstring are entirely written in Chinese, indicating a language-specific skill experience, but the file provides no user opt-in, language selection mechanism, or documented justification for restricting use to Chinese. Under the policy, forcing a specific language without user choice is a natural-language policy violation.

External Transmission

Medium
Category
Data Exfiltration
Content
def __init__(self, config: Dict):
        super().__init__(config)
        self.api_key = config.get('api_key', '')
        self.base_url = "https://api.search.brave.com/res/v1/web/search"
        self.count = config.get('count', 5)  # 返回最多5条结果
    
    def search(self, query: str) -> Optional[List[Dict]]:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code transmits the user-provided query to Brave Search via a network request, which may expose user input to a third-party service. While the module has internal docstrings and error logging, there is no user-facing warning, confirmation, or disclosure around this external data transmission in the file.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This Python file contains user-facing natural-language strings entirely in Chinese, including the module description and disclaimer. Because the skill does not present any opt-in or language selection mechanism, it may violate language/locale policy requirements for users expecting a different language.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The prominent natural-language instructions and descriptions are entirely in Chinese, including the skill name, purpose, and usage wording, with no indication that users may choose another language. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The returned metadata fields such as name and description are presented only in Chinese, and there is no user-facing option to select another language or locale. This constitutes a language policy issue because the skill appears to impose a specific language by default.

Intent-Code Divergence

Medium
Confidence
83% confidence
Finding
The metadata makes a strong privacy guarantee that all processing is local and that no user content is uploaded, but the skill also wires in a data source manager and advertises blockchain verification. In a fact-checking skill, those components commonly require network access, so the claim can mislead users into submitting sensitive text under false assumptions and may result in unintended disclosure.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The manifest description advertises very broad capabilities such as deep fact-checking, blockchain verification, configurable weighting, and scheduled verification without clearly constraining when or how the skill should be invoked. In agent ecosystems, overly broad invocation wording can cause inappropriate routing of unrelated user tasks to this skill, increasing the chance of unnecessary file access or misleading trust in its outputs.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The manifest description advertises very broad capabilities such as fact-checking, blockchain verification, configurable weighting, scheduled checking, and privacy guarantees without clearly defining invocation boundaries or trigger constraints. In agent ecosystems, overbroad descriptions can cause unintended routing or invocation in contexts the skill was not designed for, increasing the risk of misuse, overreach, or unsafe trust in its outputs.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The blockchain verification feature is presented as a built-in capability without clearly warning that checking on-chain references typically requires outbound network access to explorers, RPC endpoints, or other external services. Users may assume the feature is offline/private and unintentionally trigger external requests that expose metadata or checked content context.

Missing User Warnings

Low
Confidence
76% confidence
Finding
The code reads an API key from configuration and uses it to authenticate outbound requests, but the file does not include any visible warning or user-facing explanation that a credential is required and will be used. This is relevant under the missing-warning category for sensitive credentials in code files.

Natural-Language Policy Violations

Low
Confidence
69% confidence
Finding
The manifest description includes Chinese-language instructions and alias wording but does not state that language selection is optional or user-driven. This can create an implicit language/locale expectation without explicit opt-in.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
The file contains natural-language comments only in Chinese ("求真 v1.21 Python依赖" and "适配2核2G环境,仅使用轻量依赖"). Per the policy, forcing a specific language without offering user choice or documenting a justified locale constraint is a natural-language policy violation.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# 求真 v1.21 Python依赖
# 适配2核2G环境,仅使用轻量依赖

requests>=2.31.0
beautifulsoup4>=4.12.0
lxml>=5.1.0
nltk>=3.8.1
Confidence
93% confidence
Finding
Using requests>=2.31.0 allows future installs to resolve to different versions over time, making builds non-reproducible and weakening supply-chain assurance. If a newly published but vulnerable or malicious upstream release is pulled, deployments may become exposed without any change to this repository.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
The manifest does not pin requests to a specific version, so it is impossible to verify whether deployments will avoid the package's known advisories. In practice, this means some installations could resolve to affected versions, leaving HTTP handling exposed to issues such as credential leakage or TLS-related flaws depending on the resolved release.

Unpinned Dependencies

Low
Category
Supply Chain
Content
# 适配2核2G环境,仅使用轻量依赖

requests>=2.31.0
beautifulsoup4>=4.12.0
lxml>=5.1.0
nltk>=3.8.1
Confidence
92% confidence
Finding
beautifulsoup4>=4.12.0 is not version-pinned, so installations may drift to unreviewed releases and produce inconsistent environments. While the direct security impact is often limited by itself, it still increases supply-chain risk and reduces reproducibility.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
beautifulsoup4>=4.12.0
lxml>=5.1.0
nltk>=3.8.1
Confidence
95% confidence
Finding
lxml>=5.1.0 permits installation of any later version, which prevents reproducible builds and can silently introduce vulnerable parser behavior or malicious supply-chain changes. Because lxml commonly handles untrusted HTML/XML, dependency uncertainty is more security-relevant here than for purely utility packages.

Unverifiable Dependency: lxml has 14 known advisory(ies) (CVE-2021-43818 (lxml's HTML Cleaner allows crafted and SVG embedded scripts to pass through); CVE-2014-3146 (lxml Cross-site Scripting Via Control Characters); CVE-2021-28957 (lxml vulnerable to Cross-Site Scripting ) +11 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding
Because lxml is unpinned and has a history of security advisories, the actual installed version may be vulnerable and cannot be verified from this file alone. This is more dangerous in context because lxml is often used to parse attacker-controlled HTML/XML, where parser or sanitizer flaws can directly affect application security.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
beautifulsoup4>=4.12.0
lxml>=5.1.0
nltk>=3.8.1
Confidence
94% confidence
Finding
nltk>=3.8.1 allows uncontrolled upgrades to future versions, introducing non-deterministic builds and possible exposure to newly introduced vulnerabilities. Since NLTK may fetch or process external corpora and text inputs, version drift can have meaningful security implications.

Static analysis

No suspicious patterns detected.