Back to skill

Security audit

Finance Data Scraper

Security checks for vulnerabilities and agentic risk

Overview

The skill is a finance-data workflow, but it includes a hard-coded remote database credential and broad browser-tab closing behavior that users should review before installing.

Review this skill carefully before installing. Rotate or remove the embedded NocoDB token, require user-provided destination configuration, and run browser automation only in an isolated profile or after changing cleanup to close only tabs created by the skill.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/import_to_nocodb.py:14
Finding

Hard-Coded Live NocoDB API Credential and Fixed Remote Destination

Content
View full analysis

Vulnerability Details

File Location: scripts/import_to_nocodb.py, lines 14-21
Vulnerability Type: Hard-coded API credential and insecure secret management
Risk Level: High

Vulnerable Code

python
# NocoDB 配置 - UAT 环境
BASE_URL = "https://nocodb.dixchain.com/api/v2"
TOKEN = "TNejcEzKlX92OU0tfp3NW9PDelevPvBadZ0j-A-3"
TABLE_ID = "m2w6ubg16mcn33m"  # UAT 环境表

HEADERS = {
    "xc-token": TOKEN,
    "Content-Type": "application/json"
}

Technical Analysis

The script embeds a concrete NocoDB endpoint, table identifier, and reusable API token directly in distributed source code. Anyone with access to the project can extract the token without executing the script.

This also conflicts with the documented configuration model, which states that users should provide their own NocoDB endpoint, token, and table IDs. The example configuration is not loaded by the import script. Consequently, executing the script sends records from the selected local JSON file to the hard-coded remote NocoDB instance rather than a user-configured destination.

The exact permissions granted by the exposed token cannot be determined from the repository. However, a valid NocoDB token may permit reading, creating, updating, or deleting records depending on its assigned role and scope.

Attack Path

  1. An attacker obtains a copy of the project or otherwise reads the distributed source code.
  2. The attacker extracts the hard-coded NocoDB endpoint and API token.
  3. The attacker submits requests directly to the NocoDB API using the xc-token header.
  4. The attacker enumerates or accesses resources permitted by that token.
  5. Depending on token scope, the attacker reads sensitive records, inserts unauthorized data, modifies existing records, or deletes accessible data.

A separate data-disclosure path exists during ordinary use:

  1. A user invokes import_to_nocodb.py with a local JSON file.
  2. The script reads ...[truncated 740 chars]
Remediation
View remediation

Remediation Suggestions

  1. Revoke the exposed API token immediately and issue a replacement; removing it from the current source tree does not invalidate copies in existing distributions or repository history.
  2. Remove all real credentials, concrete private endpoints, and production or UAT table IDs from source code.
  3. Load configuration from a user-controlled file, environment variables, or a supported secret manager.
  4. Ensure import_to_nocodb.py actually consumes the documented nocodb-config.json configuration instead of silently using a fixed destination.
  5. Require explicit destination confirmation before uploading records, particularly when the endpoint is not local or belongs to another organization.
  6. Use a least-privilege token restricted to the required table and record operations.
  7. Add startup validation that rejects placeholder values, unexpected hosts, insecure HTTP endpoints, and malformed table identifiers.
  8. Keep real configuration files outside version control and provide only sanitized examples.
  9. Review NocoDB access logs for unauthorized activity performed with the exposed token.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/cleanup_tabs.py:128
Finding

Overly Broad and Destructive Browser Tab Cleanup

Content
View full analysis

Vulnerability Details

File Location: scripts/cleanup_tabs.py, lines 128-170
Vulnerability Type: Excessive browser-control scope and destructive resource cleanup
Risk Level: Medium

Vulnerable Code

python
# 策略:保留 1 个东方财富标签页,关闭其他所有标签页
tabs_to_close = []

# 如果有多个东方财富标签页,保留第一个,关闭其他
if len(eastmoney_tabs) > 1:
    tabs_to_close.extend(eastmoney_tabs[1:])
    log(f"📌 将关闭 {len(eastmoney_tabs)-1} 个多余的东方财富标签页")

# 关闭所有非东方财富标签页
if len(other_tabs) > 0:
    tabs_to_close.extend(other_tabs)
    log(f"📌 将关闭 {len(other_tabs)} 个其他标签页")

# 如果没有东方财富标签页,警告但不关闭任何东西
if len(eastmoney_tabs) == 0:
    log("⚠️ 警告:没有找到东方财富标签页!")
    log("⚠️ 为避免浏览器关闭,本次不清理任何标签页")
    log("💡 请确保主任务正常执行并打开东方财富标签页")
    return False

# 执行关闭操作
closed_count = 0
for tab in tabs_to_close:
    tab_id = tab.get("id", "")
    tab_url = tab.get("url", "unknown")[:50]

    if not tab_id:
        log(f"⚠️ 标签页无 ID,跳过:{tab_url}...")
        continue

    log(f"🗑️  关闭标签页:{tab_url}...")

    if close_tab(tab_id):
        closed_count += 1
    else:
        log(f"⚠️ 关闭失败,继续下一个")

The closing operation invoked for each selected tab is:

python
result = subprocess.run(
    ["openclaw", "browser", "close", tab_id],
    capture_output=True,
    text=True,
    timeout=30
)

Technical Analysis

The cleanup logic enumerates the entire connected browser session and marks every non-kuaixun.eastmoney.com tab for closure. It also closes all but the first matching Eastmoney tab.

The script does not restrict itself to tabs created by this Skill, a dedicated browser profile, or a tracked automation context. Domain matching is therefore used as the sole authorization boundary for a destructive browser operation. Although this behavior is disclosed in the documentation, its scope is broader than necessary for cleaning up tabs created by the finance-data workflow.

Scheduling the script through the ...[truncated 1212 chars]

Remediation
View remediation

Remediation Suggestions

  1. Run the finance automation in a dedicated browser profile or isolated browser context.
  2. Record the IDs of tabs created by this Skill and close only those explicitly tracked IDs.
  3. Do not treat every nonmatching domain as authorized for deletion.
  4. Add a dry-run mode that lists proposed closures without modifying the browser.
  5. Require explicit user confirmation before closing tabs when operating in a shared or interactive browser profile.
  6. Allow users to configure a domain allowlist and protected tab IDs.
  7. Before closing a tab, verify that it belongs to the expected automation context and was created by the current workflow.
  8. Return a nonzero exit status when enumeration or cleanup fails so scheduled monitoring can detect operational problems.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

该代码片段本身并未显示恶意或明显越权行为,其功能与声明中的第 6 项“Chrome 浏览器 Tab 清理”基本一致。但从“描述是否准确代表所提供代码片段实际行为”来看,声明将该技能描述为一个完整的财经数据抓取系统,而实际代码仅是一个标签页清理脚本,缺失声明中的绝大多数核心抓取与入库相关能力。因此应判定为描述与代码行为不匹配,属于明显的过度声明/主目的不一致。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

声明描述的核心能力是“抓取”多类财经数据并包含浏览器相关运维能力;但给出的代码块只负责将已有 JSON 数据导入远程 NocoDB 表,并做简单去重。其主要行为是本地文件读取、HTTP GET/POST 请求、数据库记录去重与写入,属于数据导入/同步脚本,而不是财经数据抓取实现。虽然声明中提到“包含入库表配置、去重规则”等,与部分导入逻辑有弱相关,但该代码缺失声明中的绝大多数核心抓取与浏览器能力,同时额外表现出明确的远程数据库写入能力。因此描述与实际代码行为存在实质性不匹配。

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script closes unrelated browser tabs across the user's session, a powerful and unjustified capability for a finance scraping skill. In context, this is more dangerous because the skill is supposed to gather market data, not control the entire browsing environment; such broad tab management can disrupt user activity, cause data loss in web apps, and mask or interfere with other tasks.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script contains hard-coded credentials and a fixed remote NocoDB endpoint, giving anyone with code access the ability to use that external service context without separate authorization. Embedding administrative or write-capable access in source code is dangerous because secrets can be leaked, reused, or abused to read/write records in the remote system.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

A hardcoded API token authenticates writes to a remote service with no user disclosure or runtime secret injection. If this code is shared, logged, or copied into other environments, the token can be extracted and used to access or manipulate the associated NocoDB data.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file uses Chinese for the skill description and instructions, but does not indicate that the language is optional or user-selectable. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language message is written entirely in Chinese and the file does not indicate that the skill is region-specific or that users can opt into this locale. That creates a language policy concern because it implicitly fixes the skill’s user-facing behavior to a single language without documented justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language instruction is written entirely in Chinese and provides no indication that language selection is optional or that the skill is intentionally limited to a Chinese-speaking or region-specific context. This can violate language/locale policy because it implicitly forces a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The natural-language message is entirely in Chinese and gives no indication that language choice is configurable or that the skill is intentionally limited to a Chinese-speaking or China-specific deployment context. This creates a locale-policy concern because the skill appears to impose a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The message field is written entirely in Chinese and provides no indication that language choice is configurable or user-selected. Under the language/locale policy, forcing a specific language without opt-in can be a policy violation unless the locale restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation claims the script only removes extra Eastmoney tabs, but the implementation also closes every non-Eastmoney tab in the user's browser session. This mismatch is dangerous because reviewers or operators may authorize the script under a narrower understanding while it performs broader, destructive actions.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/cleanup_tabs.py (reported line 24)May include surrounding context.

python
def get_browser_tabs():
    """获取当前浏览器所有标签页"""
    try:
        result = subprocess.run(
            ["openclaw", "browser", "tabs"],
            capture_output=True,
            text=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/cleanup_tabs.py (reported line 95)May include surrounding context.

python
def close_tab(tab_id):
    """关闭指定 id 的标签页"""
    try:
        result = subprocess.run(
            ["openclaw", "browser", "close", tab_id],
            capture_output=True,
            text=True,

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The cleanup strategy explicitly closes all non-Eastmoney tabs, which exceeds the stated purpose of preventing memory overflow from this skill's browser activity. In a shared user browser session, this can terminate unrelated work, destroy user context, and act as an overbroad capability with side effects outside the skill boundary.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This skill is described primarily as a finance-data scraping tool, but the script also performs bulk transmission of scraped/local data into an external NocoDB instance. That expands the trust boundary from local scraping into remote persistence, which can surprise operators and create unauthorized data-sharing risk if the destination or contents are not explicitly approved.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script uploads content from local JSON files to a remote NocoDB service automatically, but it does not clearly warn the user that local data will be transmitted externally. Even if the content is finance news, undisclosed exfiltration of local datasets can violate operator expectations, internal policy, or data-handling requirements.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This line performs external transmission of record data to a remote HTTPS endpoint. External transmission is expected for an import script, but in this skill context it is still security-relevant because the upload target and credentials are fixed in code and the data transfer is not clearly disclosed or gated.

Content

Scanner excerpt · scripts/import_to_nocodb.py (reported line 56)May include surrounding context.

python
url = f"{BASE_URL}/tables/{TABLE_ID}/records"
    
    try:
        response = requests.post(url, headers=HEADERS, json=data, timeout=30)
        response.raise_for_status()
        return True, response.json()
    except requests.exceptions.RequestException as e:

Tainted flow: 'data' from requests.get (line 34, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/import_to_nocodb.py (reported line 56)May include surrounding context.

python
url = f"{BASE_URL}/tables/{TABLE_ID}/records"
    
    try:
        response = requests.post(url, headers=HEADERS, json=data, timeout=30)
        response.raise_for_status()
        return True, response.json()
    except requests.exceptions.RequestException as e:

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The natural-language message is entirely in Chinese and provides no indication that the language is configurable or intentionally limited to a Chinese-speaking or region-specific audience. Under the policy, forcing a specific language without opt-in or clear justification is a locale-policy issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language description forces a specific language in the config text and does not offer any user language/locale choice. Under the policy, locale or language restrictions should be opt-in or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

This JSON file is a manifest-style config, so vague-trigger review applies. The only natural-language task description states a daily finance news scraping job, but it does not define any explicit trigger phrases, scope boundaries, or negative examples that clarify when this job should or should not be invoked beyond the cron schedule.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.