Back to skill

Security audit

smart-report

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its reporting purpose, but it automatically runs generated transform code and can evaluate chart JavaScript during export, so it needs careful review before installation.

Install only if you are comfortable with a reporting skill that runs local Python transforms and uses Node for optional static exports. Use it on trusted data and chart files, prefer HTML-only output when possible, avoid referencing externally supplied chart HTML, and run it in a constrained environment without sensitive environment variables if DOCX/PPTX export is needed.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/export_charts.js:119
Finding
Untrusted JavaScript Evaluation During Static Chart Export<![CDATA[ ## Vulnerability Details **File Location**: `scripts/report_assembler.py:119-143`, `scripts/report_assembler.py:333-345`, `scripts/report_assembler.py:973-1009`; `scripts/export_charts.js:119-126` **Vulnerability Type**: Evaluation of attacker-controlled JavaScript in a Node.js VM context **Risk Level**: High ### Complete Code Snippet `scripts/report_assembler.py:119-143`: ```python def _resolve_chart_path(chart_path: str, charts_dir: Path, spec_dir: Path) -> Path: """Resolve chart path: as given, beneath charts_dir, or beside the specification.""" candidates = [ Path(chart_path), charts_dir / chart_path, spec_dir / chart_path, ] for cand in candidates: if cand.is_file(): return cand return None def _extract_chart_payload(html_text: str, source: Path) -> dict: start = html_text.find(_OPT_START) if start != -1: end = html_text.find(_OPT_END, start) if end == -1: ... option_js = html_text[start + len(_OPT_START):end].strip() while option_js.endswith(';'): option_js = option_js[:-1].rstrip() if not option_js.startswith('{') or not option_js.endswith('}'): ... ``` `scripts/report_assembler.py:333-345`: ```python def _run_node_export(skill_root: Path, manifest: list, out_dir: Path, timeout: int = 60): manifest_path = out_dir / '_manifest.json' manifest_path.parent.mkdir(parents=True, exist_ok=True) manifest_path.write_text(json.dumps(manifest, ensure_ascii=False), encoding='utf-8') env = os.environ.copy() env['NODE_PATH'] = str(skill_root / 'scripts') try: proc = subprocess.run( ['node', str(skill_root / 'scripts' / 'export_charts.js'), str(manifest_path), str(out_dir)], env=env, capture_output=True, text=True, timeout=timeout, ) ``` `scripts/report_assembler.py:973-1009`: ```python charts_dir = Path(ns.charts_dir).expanduser() ...[truncated 4757 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Eliminate JavaScript evaluation for chart data** - Serialize chart options as strict JSON. - Parse them with `JSON.parse` rather than `vm.runInContext`. - Do not permit functions, getters, computed properties, prototypes, or executable expressions in the manifest. 2. **Replace executable formatters with identifiers** - Where ECharts requires formatter functions, store a fixed formatter identifier such as `"axisTooltipV1"`. - Map that identifier to a hard-coded, reviewed function inside `export_charts.js`. - Reject unknown identifiers rather than accepting arbitrary JavaScript. 3. **Constrain chart file resolution** - Canonicalize the selected file with `Path.resolve()`. - Require the canonical path to be beneath the canonical `charts_dir`. - Do not accept arbitrary absolute paths or traversal outside the designated chart directory unless an explicit trusted mode is enabled. 4. **Validate file provenance and structure** - Add a versioned metadata marker to CLI-generated chart files. - Validate the chart schema and allowed ECharts option fields before export. - Consider recording and verifying a digest of each chart artifact when the report specification is created. 5. **Apply defense-in-depth isolation** - If JavaScript execution cannot immediately be removed, provide a short timeout directly to `vm.runInContext`. - Run rendering in a resource-limited child process or container. - Disable network access and expose only required temporary input and output directories. - Clear unnecessary inherited environment variables. - Enforce process memory and CPU limits. 6. **Add adversarial tests** - Test object literals containing getters, immediately invoked functions, infinite loops, prototype manipulation, and known VM escape patterns. - Verify that non-JSON chart options and paths outside `charts_dir` are rejected before Node is invoked. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:16
Finding
Unpinned Core Dependencies Without Integrity Hashes<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:16-18` **Vulnerability Type**: Non-reproducible dependency resolution and missing package integrity pinning **Risk Level**: Low ### Complete Code Snippet `requirements.txt:16-18`: ```text pandas>=3.0.1,<4.0.0 numpy>=2.4.3,<3.0.0 openpyxl>=3.1.5,<4.0.0 xlrd>=2.0.1,<3.0.0 ``` The surrounding installation documentation instructs users to install these requirements with pip, while intentionally using compatible version ranges rather than exact pins. ### Technical Analysis The core dependencies use broad version ranges and are not accompanied by artifact hashes. As a result, two installations of the same Skill revision can resolve to different package versions and different transitive dependency graphs. The package names shown are conventional, and the audit found no evidence of typosquatting, dependency confusion, or an explicitly unsafe package index. The weakness is therefore limited to reproducibility and integrity assurance: a future release satisfying the declared range may be selected without a corresponding review or Skill update. Hashless installation also leaves the installer dependent on repository and transport trust without verifying that a specifically reviewed wheel or source archive is being installed. ### Attack Path 1. A user follows the documented pip installation process. 2. pip queries the configured package index and resolves the newest versions satisfying the ranges. 3. A newer direct or transitive dependency is selected than the version originally reviewed or tested. 4. The dependency's installation or runtime code executes in the user's Python environment. 5. If that release is compromised or unexpectedly incompatible, the Skill inherits its behavior without any change to the Skill package. This finding does not establish that any currently named dependency is malicious. ### Impact Assessment The direct impact is non-reproducible builds and increased exposure ...[truncated 388 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Maintain a reviewed lock file containing exact direct and transitive dependency versions. 2. Record SHA-256 hashes for all approved wheels or source distributions. 3. Install locked dependencies with pip's `--require-hashes` option. 4. Separate human-maintained compatibility declarations from deployment locks: - Keep ranged dependencies as development metadata if needed. - Use an exact, hashed lock file for production and automated installation. 5. Update dependencies through an explicit review process that includes vulnerability scanning, changelog review, and regression testing. 6. Configure an approved package index explicitly in controlled environments and avoid untrusted extra indexes. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (44)

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
**Numeric coercion is observable:** string columns are cleaned (currency symbols → thousands separators → `%` → Chinese magnitude suffixes `亿`/`万`/`千`, so `8.5万` → `85000`) and then coerced. If only *some* cells fail to parse but ≥50% succeed, the column still becomes numeric with the failures set to missing, and an advisory is emitted naming the column and the number of discarded cells. Below 50% the column is left as text. Previously a single stray `-` silently degraded a whole column to string with no warning.
Confidence
80% confidence
Finding
Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

exec() call detected

High
Category
Dangerous Code Execution
Content
# P2-print 修复:把 transform 代码里的 print 重定向到 stderr,
            # 避免污染 cli.py 末尾输出到 stdout 的 JSON 契约。
            with contextlib.redirect_stdout(sys.stderr):
                exec(code, ns)
        except TimeoutError:
            raise TransformError(
                f"转换代码执行超时(超过 {self.timeout} 秒),可能存在无限循环",
Confidence
96% confidence
Finding
The code executes LLM-generated Python with exec, which is inherently dangerous because the surrounding controls are blacklist/whitelist-based and therefore brittle against sandbox escape and denial-of-service techniques. In this context the risk is increased by exposing powerful live objects (pd, np, DataFrame instances) and by explicitly stating execution occurs without user confirmation, so a bypass in the validator leads directly to arbitrary code execution in the host process.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
manifest_path = out_dir / '_manifest.json'
    manifest_path.parent.mkdir(parents=True, exist_ok=True)
    manifest_path.write_text(json.dumps(manifest, ensure_ascii=False), encoding='utf-8')
    env = os.environ.copy()
    env['NODE_PATH'] = str(skill_root / 'scripts')
    try:
        proc = subprocess.run(
Confidence
83% confidence
Finding
The code copies the full parent process environment and passes it into a Node subprocess that processes dynamically assembled export input. This can leak sensitive tokens, credentials, proxy settings, or internal configuration to the child process and any libraries it loads; in this skill context, invoking an external runtime increases the chance that inherited secrets are exposed through crashes, logs, dependency behavior, or a compromised `node`/JS export path.

Lp3

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding
The skill directs the agent to use shell, file I/O, environment discovery, and potentially network-capable tooling, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an overbroad execution surface where a host agent may grant more capabilities than are actually required, increasing the risk of unintended file access, command execution, data exfiltration, or misuse if the workflow or referenced scripts are compromised.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
Line L196 says '不要主动传 --lang;CLI 自动跟随数据语言,仅当用户明确要求时才传', which imposes a language/locale behavior based on data rather than user choice. This can override the user's preferred language without explicit opt-in, matching the policy concern about forced language or locale behavior.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
This code file contains natural-language documentation and CLI help text primarily in Chinese, which imposes a specific language choice on users interacting with the skill. Although the chart output has a '--lang' option later, the CLI's own instructions and errors are still presented in Chinese by default, so the skill does not clearly offer a language choice for its operational interface.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Content
ok_all = True
    for name, min_ver in REQUIREMENTS:
        try:
            mod = __import__(name)
            ver = getattr(mod, '__version__', 'unknown')
            ok = _version_ok(ver, min_ver)
        except ImportError as e:
Confidence
75% confidence
Finding
Dynamic __import__() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This file contains natural-language instructions, comments, and CLI help text exclusively in Chinese, including the top-level module description and later argument descriptions. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation unless the regional restriction is explicitly justified, which is not present here.

Natural-Language Policy Violations

Medium
Confidence
83% confidence
Finding
Natural-language strings in the module docstring present the skill entirely in Chinese and describe its operation and safety model without any indication that language is configurable or limited for a justified regional reason. Under the policy, forcing a specific language without user opt-in is a locale-policy concern.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This component is designed to run LLM-produced code automatically and the docstring explicitly says no user confirmation is needed, removing a human safety checkpoint before dangerous behavior occurs. Because the validation model relies on syntactic filtering rather than true isolation, automatic execution materially increases the chance that prompt injection or model error becomes code execution or destructive computation.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The natural-language description throughout the module specifies the report structure, labels, and content in Chinese, indicating the generated document is designed for a fixed language/locale. The file does not offer a user language choice or explain a region-specific requirement, which conflicts with the policy against forcing a specific language without opt-in.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The module docstring and surrounding natural-language guidance are written entirely in Chinese, with no indication that language is configurable or intentionally limited to a Chinese-only context. The policy requires flagging language or locale constraints when they force a specific language without user opt-in or clear justification.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This Python file contains natural-language instructions and generated slide labels entirely in Chinese, including the module description and many hard-coded presentation strings. Under the policy rule, forcing a specific language without user opt-in is a locale/language policy violation unless the constraint is explicitly justified as region-specific.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The file’s descriptive text and remediation/error messages are written entirely in Chinese, including strings likely surfaced to users such as installation suggestions and rendering failures. This imposes a specific language/locale without any opt-in or documented justification, which matches the natural-language policy violation criteria.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_cli(args, timeout=90):
    t0 = time.time()
    proc = subprocess.run([sys.executable, str(CLI)] + [str(a) for a in args],
                          capture_output=True, text=True, timeout=timeout)
    dt = time.time() - t0
    out = None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return proc.returncode, out, proc.stderr, dt

def run_dp(args, timeout=60):
    proc = subprocess.run([sys.executable, str(DP)] + [str(a) for a in args],
                          capture_output=True, text=True, timeout=timeout)
    return proc.returncode, proc.stdout, proc.stderr
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
rec("P1-8-requirements改用兼容区间",
    'pandas>=' in _req and 'pandas==' not in _req and 'numpy>=' in _req,
    f"{_req[:80]}")
_proc = subprocess.run([sys.executable, str(CLI), '--doctor'], capture_output=True, text=True, timeout=60)
try:
    _doc = json.loads(_proc.stdout)
    rec("P1-8---doctor输出版本矩阵",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
(ROOT / 'report_spec.json').write_text(json.dumps(_spec, ensure_ascii=False), encoding='utf-8')
    # 组装(scan 模式 + 仅 html)
    _out_html = ROOT / 'report.html'
    _proc = subprocess.run([sys.executable, str(_RA), '--spec', str(ROOT / 'report_spec.json'),
                            '--charts-dir', str(_rchart_dir), '--output', str(_out_html),
                            '--ledger', str(ROOT / 'ledger.json')],
                           capture_output=True, text=True, timeout=120)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# ── R4~R10:论点台账(claims.json)形式校验 ──
    def run_ra(extra_args, out_name='report_claims.html', timeout=120):
        _proc = subprocess.run([sys.executable, str(_RA),
                                '--spec', str(ROOT / 'report_spec.json'),
                                '--charts-dir', str(_rchart_dir),
                                '--output', str(ROOT / out_name)] + [str(a) for a in extra_args],
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"annotation": "本图并列展示两条系列。"},
    ]
    (ROOT / 'report_spec_ph.json').write_text(json.dumps(_spec_ph, ensure_ascii=False), encoding='utf-8')
    _proc10 = subprocess.run([sys.executable, str(_RA),
                              '--spec', str(ROOT / 'report_spec_ph.json'),
                              '--charts-dir', str(_rchart_dir),
                              '--output', str(ROOT / 'report_ph.html'),
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
(ROOT / 'report_spec_narr.json').write_text(json.dumps(_spec_narr, ensure_ascii=False), encoding='utf-8')
    _claims_narr = [{"id": "c1", "claim": "有图章节的主张", "evidence": ["s1"], "section": "s1"}]
    (ROOT / 'claims_narr.json').write_text(json.dumps(_claims_narr, ensure_ascii=False), encoding='utf-8')
    _proc11 = subprocess.run([sys.executable, str(_RA),
                              '--spec', str(ROOT / 'report_spec_narr.json'),
                              '--charts-dir', str(_rchart_dir),
                              '--output', str(ROOT / 'report_narr.html'),
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This Python file contains natural-language documentation and inline comments entirely in Chinese, effectively imposing a specific language locale on maintainers or reviewers. The provided policy says language or locale constraints should not be forced unless the skill offers a choice or clearly documents a justified region-specific constraint, which is not present here.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
env = os.environ.copy()
    env['NODE_PATH'] = str(skill_root / 'scripts')
    try:
        proc = subprocess.run(
            ['node', str(skill_root / 'scripts' / 'export_charts.js'),
             str(manifest_path), str(out_dir)],
            env=env, capture_output=True, text=True, timeout=timeout,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This code emits `<html lang="zh-CN">` unconditionally, which forces a specific language/locale in the generated artifact. The file also consistently hard-codes Chinese UI strings, but does not expose a language option or explain that the tool is intentionally region-specific.

Natural-Language Policy Violations

Medium
Confidence
86% confidence
Finding
This code hard-codes the document language to either 'zh-CN' or 'en' based on an internal ctx.lang value, rather than exposing a user-selectable language or documenting a justified locale restriction. SQP-3 applies because it imposes a language/locale choice in natural-language behavior without clear user opt-in.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
assets/echarts.min.js:45

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/data_transformer.py:25

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/regression_check.py:149