Back to skill

Security audit

Gangtise Agent调用

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its stated Gangtise research purpose, but two scripts can send the user's Gangtise authorization token to an unvalidated API root if the environment or direct function call is influenced.

Install only if you trust the publisher and can control the runtime environment. Prefer environment-injected credentials from a secret manager, avoid scripts/.authorization when possible, do not set GANGTISE_OPENAI_ROOT to non-Gangtise URLs, and review any saved output or usage files under the Gangtise workspace.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/hot_topic.py:226
Finding

Gangtise authorization token disclosure through an unrestricted hot-topic API endpoint

Content
View full analysis
Tuple[Optional[Dict[str, Any]], Optional[str]]: url = f"{openai_root.rstrip('/')}/hot-topic/getList" headers = {"Authorization": GTS_AUTHORIZATION} resp = requests.post(url, headers=headers, json=payload, timeout=300) ``` ```python def run_hot_topic_list( page_from: int = 0, page_size: int = 20, start_date: Optional[str] = None, end_date: Optional[str] = None, category_list: Optional[List[str]] = None, with_related_securities: bool = False, with_close_reading: bool = False, output: Optional[str] = None, openai_root: Optional[str] = None, ) -> str: if not openai_root: openai_root = os.getenv("GANGTISE_OPENAI_ROOT", "https://open.gangtise.com/application/open-ai") ``` ### Technical Analysis The request destination is derived from the `openai_root` function argument or the `GANGTISE_OPENAI_ROOT` environment variable. Neither source is validated before the global Gangtise authorization token is placed in the HTTP `Authorization` header. Consequently, the request is not restricted to the declared Gangtise API origin. A caller that can invoke `run_hot_topic_list()` directly can supply any URL, while a process that can influence the execution environment can set `GANGTISE_OPENAI_ROOT`. The implementation also does not require HTTPS, so it can send the token over plaintext HTTP. Sending authenticated requests to Gangtise is necessary for the Skill's declared functionality. Allowing the credential-bearing destination to be changed to an arbitrary origin exceeds that minimum requirement. ### Attack Path 1. The attacker influences the function argument or executi ...[truncated 1082 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/security_clue.py:246
Finding

Gangtise authorization token disclosure through an unrestricted security-clue API endpoint

Content
View full analysis
Tuple[Optional[Dict[str, Any]], Optional[str]]: url = f"{openai_root.rstrip('/')}/security-clue/getList" headers = {"Authorization": GTS_AUTHORIZATION} resp = requests.post(url, headers=headers, json=payload, timeout=300) ``` ```python def run_security_clue_list( page_from: int = 0, page_size: int = 500, start_time: Optional[str] = None, end_time: Optional[str] = None, query_mode: str = "bySecurity", gts_code_list: Optional[List[str]] = None, source: Optional[List[str]] = None, output: Optional[str] = None, openai_root: Optional[str] = None, ) -> str: if not openai_root: openai_root = os.getenv("GANGTISE_OPENAI_ROOT", "https://open.gangtise.com/application/open-ai") ``` ### Technical Analysis The security-clue client accepts an unrestricted API root through a public function parameter or environment variable. It then unconditionally sends the active Gangtise authorization token to that destination. There is no validation that the destination uses HTTPS or belongs to `open.gangtise.com`. This creates a credential-exfiltration primitive whenever an attacker can influence the argument or environment. The request additionally reveals security or industry codes, time ranges, source filters, and query mode, which can disclose the user's research interests. The declared functionality only requires communication with the Gangtise API. Sending credentials to arbitrary origins is unnecessary and violates least-privilege network design. ### Attack Path 1. The attacker supplies a malicious `openai_root` argument or sets `GANGTISE_OPENAI_ROOT` in the Sk ...[truncated 949 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils.py:35
Finding

Long-lived Gangtise credentials are loaded from an unprotected plaintext file

Content
View full analysis
", "secretAccessKey":""} ``` ### Technical Analysis The Skill supports storing reusable access and secret keys in a plaintext JSON file inside the Skill directory. Before reading the file, the code does not verify ownership, reject symbolic links, or require restrictive file permissions. There is also no integration with an operating-system credential store or external secret manager. Because the file is located under the package tree, it is more likely to be copied into backups, archives, deployment bundles, or source-control commits. If permissions are inherited from a permissive directory or default creation mode, other local users or processes may also be able to read it. The implementation uses the stored access and secret keys to obtain a temporary access token. Exposure of the underlying keys may therefore be more serious than exposure of one temporary token because the keys can potentially mint new tokens repeatedly. The documentation also mentions a `long-term-token` configuration, but the audited implementation only reads `accessKey` and `secretAccessKey`. This mismatch may encourage users to experiment with additional plaintext secrets without those values being handled as described. ### Attack ...[truncated 1055 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The code substantially matches the declared overall purpose: it is a unified OpenAPI client for Gangtise research agents, returns normalized content, and includes the documented async polling behavior for earnings-review and viewpoint-debate. However, the description explicitly advertises two additional agent capabilities—hot-topic-list and security-clue-list—that are not present in AGENT_ENDPOINTS, PUBLIC_AGENT_TYPES, payload formatting, or response normalization. Since these are user-facing capabilities central to the description rather than minor implementation details, this is a material description/behavior mismatch.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares access to secrets via environment variables and documents file-based credential loading, while also invoking scripts that inherently require network, file read, and likely file write capabilities, but it does not explicitly constrain tool scope with a permissions or allowed-tools declaration. In an agent environment, this overbroad and undeclared capability surface increases the risk of unintended secret exposure, unauthorized file access, or network misuse if the skill is invoked in a broader-than-expected runtime.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code sends payloads containing inputs such as securityCode, period, viewpoint text, themeId, and dataId to an external service via requests.post. While the CLI help describes parameters and behavior, this file does not provide a user-facing warning that these inputs are transmitted over the network to a remote endpoint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The code reads an authorization value from imported configuration and attaches it to outbound HTTP headers, but this file does not disclose that a credential will be used for remote access. Under the code-file warning rule, access to sensitive credentials should have some visible explanation, prompt, or documented warning unless clearly disclosed elsewhere.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/agents.py (reported line 195)May include surrounding context.

python
def _raw_post_agent(agent_type: str, payload: Dict) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
    url = f"{GANGTISE_DATA_DOMAIN}{AGENT_ENDPOINTS[agent_type]}"
    headers = {"Authorization": GTS_AUTHORIZATION}
    resp = requests.post(url, headers=headers, json=payload, timeout=300)
    if resp.status_code != 200:
        return None, resp.text
    try:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/security_clue.py (reported line 252)May include surrounding context.

python
def _raw_post_agent(agent_type: str, payload: Dict) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
    url = f"{GANGTISE_DATA_DOMAIN}{AGENT_ENDPOINTS[agent_type]}"
    headers = {"Authorization": GTS_AUTHORIZATION}
    resp = requests.post(url, headers=headers, json=payload, timeout=300)
    if resp.status_code != 200:
        return None, resp.text
    try:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code hard-codes Chinese labels and later emits Chinese user-facing content throughout the generated markdown and CLI warnings. Because the file provides no opt-in, fallback, or documented region-specific justification, it creates a natural-language locale policy concern under the language-choice rule.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
85% confidence
Finding

The function sends request payloads and an authorization header to a URL derived from the openai_root parameter/environment variable without any allowlist or origin validation. If an attacker can influence that value, they can redirect requests and the embedded bearer credential to an attacker-controlled host, causing SSRF-style outbound connections and credential exfiltration.

Content

Scanner excerpt · scripts/hot_topic.py (reported line 232)May include surrounding context.

python
) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
    url = f"{openai_root.rstrip('/')}/hot-topic/getList"
    headers = {"Authorization": GTS_AUTHORIZATION}
    resp = requests.post(url, headers=headers, json=payload, timeout=300)
    if resp.status_code != 200:
        return None, resp.text
    try:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The function transmits access credentials to an external service to obtain a token, but this sensitive network action is not surfaced to users in a clear, user-facing way. In an agent context, undisclosed secret transmission is materially risky because users may not expect a tool invocation to send locally sourced credentials off-host.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

This code sends accessKey and secretAccessKey to an external endpoint over the network. Although this appears to be the intended authentication flow, external transmission of raw credentials is inherently sensitive and becomes more dangerous because the skill description does not clearly disclose it to users.

Content

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

python
"accessKey": ak,
        "secretAccessKey": sk
    }
    response = requests.post(AUTHORIZATION_URL, json=payload)
    if response.status_code != 200:
        return None
    try:

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/utils.py (reported line 32)May include surrounding context.

python
except Exception as e:
        return None

GTS_AUTHORIZATION = None
if GTS_ACCESS_KEY and GTS_SECRET_KEY:
    GTS_AUTHORIZATION = get_authorization(GTS_ACCESS_KEY, GTS_SECRET_KEY)
elif os.path.exists(GTS_AUTHORIZATION_PATH):

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · scripts/utils.py (reported line 41)May include surrounding context.

python
except Exception as e:
        return None

GTS_AUTHORIZATION = None
if GTS_ACCESS_KEY and GTS_SECRET_KEY:
    GTS_AUTHORIZATION = get_authorization(GTS_ACCESS_KEY, GTS_SECRET_KEY)
elif os.path.exists(GTS_AUTHORIZATION_PATH):

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The utility creates local workspace directories and later persists fetched content and usage artifacts, which is behavior broader than the retrieval-focused skill description. In an agent setting, undisclosed persistence can leak sensitive research queries/results to disk and surprise operators who expect transient processing only.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The function records usage telemetry to local JSON files without a user-facing warning or consent gate. Even if the telemetry is operational rather than highly sensitive, it can still reveal activity patterns, query volume, and potentially business-sensitive usage behavior in a research workflow.

Content

No source excerpt is available for this finding.

Tainted flow: 'process_path' from os.getenv (line 613, credential/environment) → open (file write)

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

python
return "错误信息:文件存储系统繁忙,请稍后再试"

            if GTS_SAVE_EXTENSION == "json":
                with open(process_path, "w", encoding="utf-8") as f:
                    json.dump(data_list, f, ensure_ascii=False, indent=2)
            else:
                with open(process_path, "w", encoding="utf-8") as f:

Tainted flow: 'process_path' from os.getenv (line 613, credential/environment) → open (file write)

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

python
return "错误信息:文件存储系统繁忙,请稍后再试"

            if GTS_SAVE_EXTENSION == "json":
                with open(process_path, "w", encoding="utf-8") as f:
                    json.dump(data_list, f, ensure_ascii=False, indent=2)
            else:
                with open(process_path, "w", encoding="utf-8") as f:

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code reads credentials from environment variables and a local .authorization file without that behavior being reflected in the skill description. Hidden credential access is risky in agent ecosystems because users may authorize a seemingly simple retrieval skill without realizing it will inspect local secrets sources.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code silently reads a local .authorization file for credentials if environment variables are absent. This is not inherently malicious, but undisclosed credential-file access is sensitive behavior and can violate least surprise in multi-tool agent environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The utility prepares local directories for usage and downloaded files without clear inline disclosure. In isolation this is low severity, but within a skill advertised mainly as retrieval/formatting, silent local persistence increases data handling risk and can expose sensitive research content to other local processes or future users of the workspace.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The main diagnostic output repeatedly states it is checking and reporting status for 'gangtise-kb', which conflicts with this file's apparent role in the Gangtise agent/OpenAPI skill. This can mislead developers about what component is being validated and what configuration the script applies to.

Content

No source excerpt is available for this finding.