Back to skill

Security audit

Financial data fetcher

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a TongdaXin finance-data toolkit, but it also includes under-disclosed live trading, destructive client-state changes, and unsafe file-writing capabilities that require user review before installation.

Install only if you intentionally want an agent to control a local TongdaXin TQ environment, and treat it as write-capable rather than read-only. Avoid using it with a logged-in trading account unless trading functions are removed or separately gated, and review sector deletion/clearing plus print_to_tdx file export behavior before allowing automated use.

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

T09 · Insecure Skill Coding Practices

Error
Location
lib/tqcenter.py:725
Finding
Path Traversal Enables Arbitrary File Deletion and Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `lib/tqcenter.py`, lines 725–770 and 775–833 **Vulnerability Type**: Path traversal and unrestricted file overwrite **Risk Level**: High ### Vulnerable Code ```python with open(xml_filename, "w", encoding="gbk") as f: f.write(xml_content) json_dir = os.path.join(tdx_root_path, r"T0002\cloud_cache\list") os.makedirs(json_dir, exist_ok=True) for g_idx in range(group_count): current_df = df_list[g_idx] jsn_file = jsn_filenames[g_idx] col_header = ["date"] + [ f"code_g{g_idx + 1}_t1_{j}" for j, _ in enumerate(current_df.columns[1:], 1) ] data_rows = [] for _, row in current_df.iterrows(): date_str = ( row.iloc[0].strftime("%Y-%m-%d") if pd.api.types.is_datetime64_any_dtype(current_df.iloc[:, 0]) else str(row.iloc[0]) ) vals = [] for v in row.iloc[1:]: try: vals.append(float(v)) except: vals.append(str(v) if pd.notna(v) else "") data_rows.append([date_str] + vals) with open(jsn_file, "w", encoding="utf-8") as f: json.dump( [{"colheader": col_header, "data": data_rows}], f, ensure_ascii=False, indent=2 ) jsn_target = os.path.join(json_dir, jsn_file) if os.path.exists(jsn_target): os.remove(jsn_target) shutil.move(jsn_file, jsn_target) xml_dir = os.path.join(tdx_root_path, r"T0002\cloud_cfg") os.makedirs(xml_dir, exist_ok=True) xml_target = os.path.join(xml_dir, xml_filename) if os.path.exists(xml_target): os.remove(xml_target) shutil.move(xml_filename, xml_target) ``` The SP filename is handled in the same unsafe manner: ```python pad_dir = os.path.join(tdx_root_path, r"T0002\pad") os.makedirs(pad_dir, exist_ok=True) sp_file = f"{sp_name}.sp" if sp_name else "python.sp" sp_path = os.path.join(pad_dir, sp_file) with open(sp_path, "w", enco ...[truncated 2295 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only basename-style filenames: - Reject absolute paths. - Reject `/`, `\`, `..`, drive prefixes, and null bytes. - Apply conservative character restrictions such as `^[A-Za-z0-9_-]+\.xml$`. 2. Enforce the expected extension independently for each output: - XML files must end in `.xml`. - JSON files must end in `.jsn` or the documented extension. - SP files must end in `.sp`. 3. Resolve and verify every destination before writing: ```python def safe_destination(root: Path, supplied_name: str, extension: str) -> Path: if Path(supplied_name).name != supplied_name: raise ValueError("Only simple filenames are permitted") if not supplied_name.lower().endswith(extension): raise ValueError(f"Filename must end with {extension}") root = root.resolve() destination = (root / supplied_name).resolve() destination.relative_to(root) return destination ``` 4. Write directly to a validated destination rather than first creating a file in the current working directory. 5. Use a securely created temporary file in the validated target directory and perform an atomic `os.replace()` only after serialization succeeds. 6. Do not automatically delete an existing file unless replacement is explicitly requested and authorized. 7. Run the exporter under a low-privilege account that has write access only to the required TongdaXin data directories. 8. Add automated tests covering absolute paths, Windows drive paths, UNC paths, mixed separators, encoded traversal, and repeated `..` components. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
lib/tqcenter.py:677
Finding
Unescaped Values Permit TongdaXin XML and SP Configuration Injection<![CDATA[ ## Vulnerability Details **File Location**: `lib/tqcenter.py`, lines 677–706, 725–726, and 775–833 **Vulnerability Type**: XML attribute injection and configuration-file injection **Risk Level**: Medium ### Vulnerable Code ```python current_title = final_table_titles[group_idx] xml_content += f''' <table X="0" Y="-1" width="1" height="36" isleaf="true" id="{cond_id}" name="condpanel"> <condpanel> <ctrls rowcount="1" frameline="10"> <ctrl rowindex="0" index="1" text="{current_title}" type="static" hoffset="10" align="L" width="120" fontsize="-14"></ctrl> <ctrl rowindex="0" index="2" text="运行时间:{run_time}" type="static" hoffset="10" align="L" width="200" fontsize="-14"></ctrl> </ctrls> </condpanel> </table> ''' ``` DataFrame column names and JSON filenames are also interpolated into XML attributes without escaping: ```python sp_names = current_df.columns[1:].tolist() for j, fname in enumerate(sp_names, 1): col_name = f"code_g{group_idx + 1}_t1_{j}" xml_content += f'\t\t\t\t\t\t\t\t<gridcol name="{col_name}" caption="{fname}" visible="true" filter="true" align="R" headalign="R" width="120" datatype="S"/>\n' xml_content += f''' </gridcols> <datasource reqformat="11" condid="{cond_id}" name="" body="list/{current_jsn}"/> </gridctrl> </table> ''' ``` SP configuration values are similarly inserted without format-aware escaping: ```python sp_file = f"{sp_name}.sp" if sp_name else "python.sp" sp_path = os.path.join(pad_dir, sp_file) sp_content = f'''[DEAFULTGP] Name={sp_name} ShowName= CmdNum=2 UnitNum=1 KeyGuyToExtern=0 ForceUseDS=0 PadMaxCx=0 PadMaxCy=0 PadHelpStr=运行时间:{run_time} # 记录运行时间 PadHelpUrl= HasProcessBtn=0 UnSizeMode=0 HQGridNoCode=0 crTipWord=0 Fix ...[truncated 2593 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Generate XML through a structured XML API such as `xml.etree.ElementTree` or `lxml` rather than string interpolation. 2. If string generation cannot immediately be removed, escape all XML attribute values with a standards-compliant XML escaping function. Do not rely on ad hoc replacement. 3. Validate all identifiers: - Restrict `sp_name`, XML names, and JSON names to a conservative allowlist. - Reject carriage returns, line feeds, control characters, quotes, angle brackets, and path separators. - Set explicit maximum lengths. 4. Treat DataFrame column names as untrusted input and encode them before placing them in XML. 5. Serialize SP configuration with a format-aware writer. If the format has no safe serializer, reject newline and delimiter characters from all externally derived values. 6. Keep display labels separate from filesystem and configuration identifiers. Human-readable titles may be encoded, while identifiers should use generated values. 7. Parse the generated XML before installation and fail closed if it is not well formed. 8. Add tests using payloads containing quotes, ampersands, angle brackets, carriage returns, line feeds, and injected section headers. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
lib/tqcenter.py:2240
Finding
Data-Fetching Skill Exposes an Undeclared Native Order-Submission Interface<![CDATA[ ## Vulnerability Details **File Location**: `lib/tqcenter.py`, lines 34 and 2240–2289 **Vulnerability Type**: Excessive capability and missing authorization controls for financial orders **Risk Level**: High ### Vulnerable Code The native order function is bound when the module is imported: ```python dll.SetNewOrder.restype = ctypes.c_char_p ``` The library then exposes an order-submission method: ```python @classmethod def order_stock(cls, account: str, stock_code: str, order_type: int, order_volume: int, price_type: int, price: float, strategy_name: str, order_remark: str = ''): """下单接口 暂无实际功能""" cls._auto_initialize() if not account: cls.close() raise ValueError("必传参数缺失:account不能为空,请提供账户信息") if not stock_code: cls.close() raise ValueError("必传参数缺失:stock_code不能为空,请提供合约代码") if not check_stock_code_format(stock_code): tq.close() raise ValueError(f"{stock_code}异常") try: account_str = account.encode('utf-8') code = stock_code.encode('utf-8') if order_remark is not None: remark = order_remark.encode('utf-8') timeout_ms = 5000 ptr = dll.SetNewOrder( cls._get_run_id(), account_str, code, order_type, order_volume, price_type, price, remark, timeout_ms ) if len(ptr) > 0: result_str = ptr.decode('utf-8') data_json = json.loads(result_str) if data_json.get("ErrorId") != "0": print(f"下单{stock_code}数据错误: {data_json}") return -1 return data_json return -1 except Exception as e: print(f"下单{stock_code}数据异常: {e}") import traceback traceback.print_exc() return -1 ``` ...[truncated 2299 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `order_stock()` and the `SetNewOrder` binding from this data-fetching Skill. 2. If trading support is required, move it into a separate package or module with independently granted permissions and an explicit trading-oriented description. 3. Disable trading by default and require a deliberate configuration setting, such as `ENABLE_LIVE_TRADING=true`, before loading the native order function. 4. Require explicit confirmation containing the account, symbol, side, quantity, limit price, and estimated notional value. 5. Add enforceable controls: - Account allowlists. - Symbol and market allowlists. - Maximum quantity and notional limits. - Allowed order and price types. - Trading-hour checks. - Daily aggregate limits. - Duplicate-order and idempotency protections. 6. Provide a dry-run mode and make it the default. Live mode should be visually and programmatically distinct. 7. Add immutable audit logging for each attempted and completed order, excluding unnecessary sensitive account details. 8. Correct the misleading method documentation. The code must not claim that the interface is nonfunctional while calling a native submission function. 9. Require the native component to enforce authorization as a second control layer rather than relying exclusively on Python-side validation. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (104)

Context-Inappropriate Capability

Critical
Confidence
99% confidence
Finding
The order_stock function invokes dll.SetNewOrder with user-supplied account, symbol, size, and price parameters, which appears to submit live trading orders. In a skill presented as data-fetching, this creates a severe integrity and financial-risk issue because any agent or user expecting read-only behavior could trigger real transactions without realizing the capability exists.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
A tool advertised as data retrieval also includes commands that modify custom sectors and other persistent state. That kind of description-behavior mismatch is dangerous because automated selection logic may invoke the skill for ordinary finance queries without anticipating side effects.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
A tool advertised as data retrieval also includes commands that modify custom sectors and other persistent state. That kind of description-behavior mismatch is dangerous because automated selection logic may invoke the skill for ordinary finance queries without anticipating side effects.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
The send_user_block function modifies the user's watchlist/custom sector state through SetResToMain, which is a persistent client-side side effect unrelated to simple data retrieval. This can silently alter a user's environment, mislead downstream workflows, or be abused to inject unwanted symbols into monitored lists.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The skill is described as a financial data fetcher, but this file exposes capabilities well beyond read-only data access, including order placement and client-state modification. This mismatch is dangerous because a caller or orchestrator may grant the skill broader trust than intended, enabling unauthorized trades or persistent client changes under the guise of data retrieval.

Missing User Warnings

High
Confidence
96% confidence
Finding
Order placement is exposed as a direct function call with no user-facing warning, confirmation, or secondary approval step. This makes accidental, coerced, or policy-bypassing trade execution much easier, especially in an agent context where tools may be invoked automatically.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The docstring for the order interface says it has no actual function, yet the implementation calls SetNewOrder and processes the returned result as if the order were real. Misleading documentation around a destructive financial action is dangerous because reviewers, operators, or policy layers may underestimate the risk and allow code that can place trades.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The example code exposes arbitrary local file transmission via tq.send_file(file), while the skill is described only as a financial data fetcher. A capability to send local files to a client can be abused for unintended data exfiltration or movement of sensitive local content, especially when users do not expect file-transfer behavior from this skill.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
A local file upload primitive is not justified by the stated purpose of fetching financial data, so it represents unnecessary and risky functionality. In the context of an agent skill, this mismatch is especially dangerous because operators may authorize the skill for benign market-data tasks while unknowingly enabling transfer of arbitrary local files to an external client.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The code packages buy/sell signals into structured warnings via send_warn and the surrounding instructions say users can quickly open lightning buy/sell interfaces from those signals. Even if it does not place orders directly, it materially shortens the path from model output to trade execution, increasing the risk of unintended, manipulated, or insufficiently reviewed trading actions.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The script performs a destructive state-changing operation (`clear_sector`) that removes all constituents from a custom sector, which conflicts with the skill's stated purpose as a financial data retrieval tool. This mismatch increases the risk of accidental or unexpected destructive use, especially if operators assume the package is read-only and run it in automation or with elevated access.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The script performs a destructive action by deleting a custom sector via `tq.delete_sector`, which conflicts with the stated skill purpose of financial data retrieval. This mismatch increases the risk of unintended or hidden destructive behavior, especially if the skill is installed or invoked under the assumption that it is read-only.

Lp3

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding
The skill documents commands that can write to the local system or modify application state, but it does not declare any explicit tool scope or permission boundary. In an agent setting, missing scope declarations increases the chance that file-writing or state-changing actions are invoked without clear authorization or review.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The documented command set mixes data-fetching operations with management actions such as custom-sector modification, cache refresh, and downloading files. In a security-sensitive agent ecosystem, combining safe and mutating actions under one broad finance skill increases accidental misuse and weakens the principle of least privilege.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger conditions are extremely broad, covering essentially any stock, market, or financial-data-related request. Overbroad triggers make unintended activation more likely, which is especially risky when the same skill includes write, download, refresh, or subscription capabilities beyond simple lookup behavior.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The custom-sector commands include create, delete, rename, add-members, and clear operations, but the documentation provides no warning that these are destructive or persistent changes. A user or agent could unintentionally alter watchlists or sector organization, causing loss of user configuration and downstream decision errors.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The print_to_tdx function creates, overwrites, deletes, and moves XML/JSON/SP files into client directories, changing local application state rather than merely returning fetched data. In a supposedly read-only financial data skill, hidden filesystem writes increase the risk of persistence, configuration tampering, or unanticipated client behavior.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The file export logic overwrites existing files, removes targets, and moves generated artifacts into application directories without clear disclosure at the API boundary. Undisclosed destructive filesystem operations can damage user configuration, create persistence, or surprise higher-level systems that assumed the skill was read-only.

Whitespace Padding

Medium
Category
Prompt Injection
Content
for i, date in enumerate(dates):
                        if i < len(values):
                            ts = f"{date}{int(times[i]):06d}" if i < len(times) and times[i] not in ("0", "000000",
                                                                                                     "0000") else date
                            if ts in ts_to_idx:
                                try:
                                    v = float(values[i]) if values[i] else np.nan
Confidence
70% confidence
Finding
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The quote subscription docstring claims there is no actual function, but the code registers callbacks and subscribes through the DLL, enabling ongoing external data flow into the process. While less severe than order placement, misleading documentation about active subscriptions can bypass review expectations and create hidden runtime behavior and trust-boundary issues.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The delete_sector function can remove a custom sector with no confirmation or destructive-action warning. In a tool marketed for data fetching, exposing silent deletion of user state raises the risk of accidental loss or misuse by automated workflows.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The clear_sector function can wipe a custom sector's contents without an explicit warning or approval step. This can destroy user-curated watchlist state and is especially risky when bundled inside a skill whose declared purpose does not imply destructive client mutations.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The markdown file presents all headings, parameter descriptions, and example outputs in Chinese only, including sample categorical text values such as industry/concept labels. Under the policy rule, forcing a specific language without opt-in or a documented regional justification is a natural-language policy violation.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The documented API performs state-changing client actions by adding or clearing stocks in user-defined sectors, which exceeds the skill's stated purpose of financial data fetching. This mismatch can mislead users or calling agents into invoking a mutating operation when they expect read-only behavior, increasing the risk of unintended portfolio/watchlist modification.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation states that providing an existing block_code with an empty stock list will clear all stocks in that block, but it does not present this as a destructive action or warn users about the consequence. In an agent-driven workflow, this could lead to accidental deletion of user-maintained custom sector contents through parameter mistakes or misunderstood defaults.

Static analysis

No suspicious patterns detected.