Back to skill

Security audit

DataEase

Security checks for vulnerabilities and agentic risk

Overview

This skill does the DataEase export work it claims, but it handles live DataEase tokens in ways that could expose them during browser capture.

Install only in a controlled environment with a trusted HTTPS DataEase URL. Use a least-privilege, short-lived account or token, avoid command-line passwords where possible, treat terminal logs and exported files as sensitive, and review or patch the browser capture code before using it with production data.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/browser_capture.mjs:309
Finding

DataEase Authentication Token Is Sent to Unrelated Origins

Content
View full analysis

Vulnerability Details

File Location: scripts/browser_capture.mjs:309-350
Vulnerability Type: Authentication token disclosure through unrestricted browser headers
Risk Level: High

Vulnerable Code:

javascript
const context = await browser.newContext({
  viewport: { width, height },
  deviceScaleFactor: 1,
  ignoreHTTPSErrors: true,
  extraHTTPHeaders: {
    'X-DE-TOKEN': token
  }
});
await context.route('**/de2api/**', async route => {
  const request = route.request();
  const headers = {
    ...request.headers(),
    'X-DE-TOKEN': token
  };
  const url = request.url();
  if (url.includes('/de2api/outerParams/getOuterParamsInfo/')) {
    try {
      const response = await route.fetch({ headers });
      if (response.status() < 500) {
        await route.fulfill({ response });
        return;
      }
      debugLogs.push(`outerParams fallback: ${response.status()} ${url}`);
    } catch (error) {
      debugLogs.push(`outerParams fallback error: ${error?.message || String(error)}`);
    }
    await route.fulfill({
      status: 200,
      contentType: 'application/json;charset=UTF-8',
      body: JSON.stringify({
        code: 0,
        msg: 'success',
        data: {
          outerParamsInfoMap: {},
          outerParamsInfoBaseMap: {}
        }
      })
    });
    return;
  }
  await route.continue({ headers });
});

Technical Analysis

The extraHTTPHeaders option applies X-DE-TOKEN to every request made by the browser context, rather than only to requests sent to the configured DataEase origin. Although the subsequent route handler targets paths matching **/de2api/**, that route does not restrict or override the global behavior for other requests.

A rendered dashboard may load third-party images, scripts, fonts, frames, tracking resources, or attacker-controlled URLs. Requests to those origins can consequently car ...[truncated 1116 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove extraHTTPHeaders from the browser context.
  • Parse and validate the configured DataEase URL before launching the browser.
  • Add the token only in a route handler that verifies both the exact trusted origin and the expected /de2api/ path prefix.
  • Explicitly strip X-DE-TOKEN, Authorization, cookies, and other credentials from cross-origin requests.
  • Consider blocking unnecessary third-party requests during capture.
  • Reject redirects from the trusted DataEase origin to an untrusted origin.
  • Use a short-lived, capture-specific token with the smallest available resource and organization scope.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/browser_capture.mjs:309
Finding

TLS Certificate Validation Is Disabled and Plaintext Service URLs Are Accepted

Content
View full analysis

Vulnerability Details

File Location: scripts/browser_capture.mjs:309-315
Vulnerability Type: Improper transport security validation
Risk Level: High

Vulnerable Code:

javascript
const context = await browser.newContext({
  viewport: { width, height },
  deviceScaleFactor: 1,
  ignoreHTTPSErrors: true,
  extraHTTPHeaders: {
    'X-DE-TOKEN': token
  }
});

Related unrestricted base URL configuration at scripts/capture_dashboard.py:720-727:

python
def add_common_auth_args(parser):
    parser.add_argument("--base-url", default=os.getenv("DATAEASE_BASE_URL", ""))
    parser.add_argument("--access-key", default=os.getenv("DATAEASE_ACCESS_KEY", ""))
    parser.add_argument("--secret-key", default=os.getenv("DATAEASE_SECRET_KEY", ""))
    parser.add_argument("--username", default=os.getenv("DATAEASE_USERNAME", ""))
    parser.add_argument("--password", default=os.getenv("DATAEASE_PASSWORD", ""))
    parser.add_argument("--login-origin", type=int, default=int(os.getenv("DATAEASE_LOGIN_ORIGIN", "0")))
    parser.add_argument("--request-mode", default=os.getenv("DATAEASE_REQUEST_MODE", "auto"), choices=["auto", "gateway", "backend"])

Technical Analysis

Setting ignoreHTTPSErrors: true disables certificate-error enforcement for the Playwright browser context. The Python entry point also accepts any base URL without requiring HTTPS or validating the destination hostname.

Authentication headers, session tokens, rendered dashboard contents, and API responses may therefore be transmitted over an unauthenticated TLS connection or over plaintext HTTP. Encryption of login fields does not replace server authentication or protect the later bearer token and dashboard traffic.

Attack Path

  1. A user configures an HTTP DataEase URL, encounters a server with an invalid certificate, or connects through a network controlled by an attacker.
  2. The attacker intercepts DNS or ne ...[truncated 827 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove ignoreHTTPSErrors: true and retain normal certificate verification.
  • Require an https:// base URL by default.
  • Validate the parsed hostname against an administrator-configured allowlist.
  • Reject URLs containing unexpected user information, schemes, or malformed hostnames.
  • If development environments require self-signed certificates, install a trusted private CA rather than disabling validation.
  • If an insecure development override is unavoidable, require an explicit flag, display a prominent warning, and prohibit its use with production credentials.
  • Apply the same origin and transport validation to all Python API calls and browser navigation.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/capture_dashboard.py:515
Finding

Passwords and Session Tokens Are Exposed Through Process Arguments and Command Output

Content
View full analysis

Vulnerability Details

File Location: scripts/capture_dashboard.py:515-533
Vulnerability Type: Sensitive credential exposure
Risk Level: Medium

Vulnerable Code:

python
width, height = parse_pixel(pixel)
cmd = [
    "node",
    str(BROWSER_CAPTURE_SCRIPT),
    "--url",
    preview_url,
    "--token",
    x_de_token,
    "--width",
    str(width),
    "--height",
    str(height),
    "--wait-seconds",
    str(ext_wait_time),
    "--result-format",
    str(result_format),
    "--output",
    str(output_path),
]

Password-bearing command-line support at scripts/capture_dashboard.py:720-727:

python
def add_common_auth_args(parser):
    parser.add_argument("--base-url", default=os.getenv("DATAEASE_BASE_URL", ""))
    parser.add_argument("--access-key", default=os.getenv("DATAEASE_ACCESS_KEY", ""))
    parser.add_argument("--secret-key", default=os.getenv("DATAEASE_SECRET_KEY", ""))
    parser.add_argument("--username", default=os.getenv("DATAEASE_USERNAME", ""))
    parser.add_argument("--password", default=os.getenv("DATAEASE_PASSWORD", ""))
    parser.add_argument("--login-origin", type=int, default=int(os.getenv("DATAEASE_LOGIN_ORIGIN", "0")))
    parser.add_argument("--request-mode", default=os.getenv("DATAEASE_REQUEST_MODE", "auto"), choices=["auto", "gateway", "backend"])

Token output at scripts/capture_dashboard.py:918-935:

python
switch_result = switch_organization(args.base_url, switch_headers, args.org_id)
switch_data = extract_response_data(switch_result, "切换组织")
x_de_token = switch_data.get("token") if isinstance(switch_data, dict) else None
if not x_de_token:
    raise ValueError("切换组织接口未返回 data.token")
print_json({
    "ok": True,
    "stage": "switch_org",
    "org_id": str(args.org_id),
    "x_de_token": x_de_token,
    "token_exp": switch_data.get("exp"),
    "token_source": "switched_org",
    "auth_mode"
...[truncated 1797 chars]
Remediation
View remediation

Remediation Suggestions

  • Pass the browser token through stdin, an inherited file descriptor, or another protected IPC channel instead of a command-line argument.
  • Remove or deprecate --password, --secret-key, and direct token arguments for interactive use.
  • Read passwords through a non-echoing prompt or a protected secret provider.
  • Prefer environment variables only where the runtime prevents unauthorized environment inspection.
  • Do not print bearer tokens by default. Return token expiry, organization context, and a redacted identifier instead.
  • If token export is necessary for a specific workflow, require an explicit opt-in flag and write it to a permission-restricted file rather than stdout.
  • Update the README examples so that they do not encourage passwords on the command line.
  • Ensure logs and exception handlers redact passwords, access keys, secret keys, signatures, and DataEase tokens.

T08 · Insecure Dependencies

Warning
Location
package.json:9
Finding

Runtime Dependencies Are Not Reproducibly Pinned

Content
View full analysis

Vulnerability Details

File Location: package.json:9-12
Vulnerability Type: Non-reproducible third-party dependency resolution
Risk Level: Medium

Vulnerable Code:

json
"dependencies": {
  "pdf-lib": "^1.17.1",
  "playwright": "^1.53.0"
},

Technical Analysis

The dependency declarations use caret version ranges, and the reviewed project structure contains no package lockfile. A future npm install may therefore resolve dependency versions different from those reviewed during this audit.

No malicious dependency was identified in the supplied files. The security issue is that installation is not reproducible and later compatible releases can enter the execution environment without repository-level review. Playwright and its transitive dependencies execute with the privileges of the Skill process and interact with sensitive authentication material and exported dashboard data.

Attack Path

  1. A developer or deployment environment runs npm install.
  2. npm resolves versions permitted by the caret ranges at installation time.
  3. A newly published, compromised, or otherwise unsafe compatible release is selected.
  4. Package installation or runtime loading executes the affected dependency with the Skill process's privileges.
  5. The compromised component can access local files available to the process, browser data, output files, or tokens supplied during capture.

Impact Assessment

A compromised dependency could execute arbitrary code with the operating-system privileges of the Skill process. Potential exposure includes DataEase credentials, session tokens, generated reports, environment variables, and files accessible to the runtime account. The practical likelihood depends on a future dependency or supply-chain compromise; no such compromise was confirmed in the audited package versions.

Remediation
View remediation

Remediation Suggestions

  • Generate and commit a reviewed package-lock.json.
  • Use npm ci in deployment and CI environments so installation matches the lockfile exactly.
  • Review resolved transitive dependencies and lockfile integrity hashes.
  • Consider exact top-level versions rather than broad version ranges.
  • Enable automated vulnerability and provenance checks for dependency updates.
  • Review and test dependency upgrades before updating the lockfile.
  • Restrict npm registry configuration to trusted registries and use a controlled installation environment.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (26)

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 · README.md (reported line 33)May include surrounding context.

  1. 复制环境变量模板:
bash
cp .env.example .env
  1. 安装本地截图依赖:

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
- 使用 `scripts/browser_capture.mjs` 打开预览页并完成本地截图

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/capture_dashboard.py (reported line 672)May include surrounding context.

python
print_json({
            "ok": False,
            "stage": "config",
            "error": "缺少必需配置,请通过命令行参数、系统环境变量或 .env 提供",
            "missing": ["DATAEASE_BASE_URL"],
        }, 1)

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/capture_dashboard.py (reported line 1056)May include surrounding context.

python
def main():
    load_dotenv(ROOT_DIR / ".env")
    args = parse_args()
    auth_context = load_auth(args)

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The README documents use of usernames, passwords, access keys, tokens, and browser localStorage token injection for export workflows, but does not warn users about handling sensitive credentials, storage risks, output sensitivity, or exposure through logs and screenshots. In a skill that captures authenticated dashboards, this omission increases the chance of accidental credential leakage or export of sensitive business data to local files or shared environments.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill describes capabilities that require environment-variable access, filesystem read/write, network calls, and shell execution, but it does not declare any explicit tool scope or permission boundaries. That creates an over-privileged, ambiguous execution model where an agent may invoke sensitive operations without clear constraints, increasing the risk of credential exposure, arbitrary command execution, unintended network access, or writing exported data to unsafe locations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation explicitly instructs the workflow to inject a live authentication token into browser localStorage for rendering preview pages. Storing bearer-style tokens in localStorage increases exposure to theft through browser automation mistakes, local inspection, debugging artifacts, or any XSS in the preview application, and the doc provides no warning or containment guidance.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The authentication section instructs operators to configure highly sensitive secrets including username, password, access key, and secret key, and describes custom token/signing logic, but omits any guidance on secure storage, rotation, masking, or least-privilege use. In a skill intended for automated export and org switching, this increases the risk of credential leakage, misuse across organizations, and unsafe copy-paste into scripts or logs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script accepts an authentication token and injects it into browser request headers for all matching /de2api/ requests, while also running against a user-supplied URL and with ignoreHTTPSErrors: true. In this skill context, that creates meaningful credential exposure risk if the target URL is malicious, misconfigured, or intercepted, because the token can be sent to an untrusted endpoint without strong transport validation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script writes the authentication token into localStorage (user.token and related keys) before loading a user-provided page. Any JavaScript executing in that origin, including compromised app code or injected third-party content, can read localStorage and steal the token, making this especially sensitive for a browser automation skill that navigates to dynamic web content.

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/capture_dashboard.py (reported line 177)May include surrounding context.

python
"-iv",
        iv.encode("utf-8").hex(),
    ]
    proc = subprocess.run(cmd, input=plain_text.encode("utf-8"), capture_output=True, check=False)
    if proc.returncode != 0:
        stderr = proc.stderr.decode("utf-8", errors="replace").strip()
        raise RuntimeError(stderr or "openssl 加密失败")

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/capture_dashboard.py (reported line 311)May include surrounding context.

python
"-iv",
        b"0000000000000000".hex(),
    ]
    proc = subprocess.run(cmd, input=cipher_text.encode("utf-8"), capture_output=True, check=False)
    if proc.returncode != 0:
        stderr = proc.stderr.decode("utf-8", errors="replace").strip()
        raise RuntimeError(stderr or "openssl 解密 dekey 失败")

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/capture_dashboard.py (reported line 338)May include surrounding context.

python
with tempfile.TemporaryDirectory(prefix="dataease-pubkey-") as tmpdir:
        key_path = Path(tmpdir) / "public.pem"
        key_path.write_text(format_public_key(public_key), encoding="utf-8")
        proc = subprocess.run(
            ["openssl", "pkeyutl", "-encrypt", "-pubin", "-inkey", str(key_path)],
            input=plain_text.encode("utf-8"),
            capture_output=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code performs remote authentication by encrypting and sending username/password to login endpoints, and elsewhere exchanges and uses access keys and tokens in HTTP headers. Although these operations are central to the script's function, the file itself provides no docstring, comments, or user-facing notice warning that sensitive credentials and tokens will be transmitted to the configured server.

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/capture_dashboard.py (reported line 540)May include surrounding context.

python
"--output",
        str(output_path),
    ]
    proc = subprocess.run(
        cmd,
        cwd=str(ROOT_DIR),
        capture_output=True,

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The entire skill documentation is written in Chinese, and the example natural-language requests are also Chinese-only, with no indication that other languages are supported or that Chinese is a required locale for a region-specific deployment. Under the stated policy, forcing a specific language without opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest description is written entirely in Chinese, which can indicate a language-specific experience without offering any language choice or documenting a locale-specific constraint. Under the policy criteria, natural-language content that imposes a language/locale without opt-in should be flagged unless clearly justified.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

Using a caret range for pdf-lib allows installation of newer dependency versions than the one originally tested, which can reduce build reproducibility and unexpectedly introduce vulnerable or breaking releases through the supply chain. In a skill that exports screenshots or PDFs, dependency integrity matters because these libraries process generated output and run in the execution environment.

Content

Scanner excerpt · package.json (reported line 10)May include surrounding context.

json
"test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "pdf-lib": "^1.17.1",
    "playwright": "^1.53.0"
  },
  "repository": {

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

Using a caret range for playwright permits automatic uptake of newer releases, weakening reproducibility and increasing supply-chain risk if a compromised or vulnerable version is resolved at install time. This is more sensitive here because Playwright executes browser automation and typically downloads browser binaries, expanding the trust boundary beyond a simple utility library.

Content

Scanner excerpt · package.json (reported line 11)May include surrounding context.

json
},
  "dependencies": {
    "pdf-lib": "^1.17.1",
    "playwright": "^1.53.0"
  },
  "repository": {
    "type": "git",

Unverifiable Dependency: playwright has 1 known advisory(ies) (CVE-2025-59288 (Playwright downloads and installs browsers without verifying the authenticity of)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The manifest includes playwright without exact version pinning, while the package has a known advisory related to downloading and installing browsers without authenticity verification. Because the installed version is not fixed, consumers may resolve to an affected release, creating a supply-chain exposure that is particularly relevant for a browser-automation skill.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

This JSON file contains user-facing natural-language resource names exclusively in Chinese, which can impose a specific language/locale without any visible opt-in or justification. Under the policy, forcing a specific language is a natural-language policy concern unless the locale restriction is explicitly documented or optional.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script writes generated PDF output to the path provided by the user, but the file contains no warning beyond the bare option name indicating that it will create or overwrite a file. For code files, file-write behavior should have some visible disclosure when no prompt, comment, or broader skill description is present.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The locator.screenshot call saves image data directly to the user-supplied output path, which is a filesystem write operation. Although expected for a capture script, there is no explicit warning that the path will be written, and no overwrite notice or confirmation is present in this file.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.