Back to skill

Security audit

AIDSO 虾搜 GEO

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its AIDSO GEO service purpose, but its API-key binding flow sends the secret as ordinary content to a remote knowledge endpoint and stores keys locally in plaintext.

Review before installing. Use a low-privilege AIDSO key if possible, rotate any key previously bound with this version, avoid entering secrets in normal chat or shell history, and remove artifact/.env when no longer needed. Be especially cautious with GEO_API_BASE_URL or any wrapper environment because it can change where authenticated question-mining requests are sent.

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
bind_api_key.py:110
Finding

API Key Sent as Knowledge-Base Business Content During Binding

Content
View full analysis
Dict[str, Any]: """ Call the binding validation endpoint. """ payload = { "content": api_key, "brand_name": api_key, } headers = { "x-api-key": api_key, "Content-Type": "application/json", } try: response = requests.post( BIND_URL, headers=headers, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), timeout=30, ) ``` ### Technical Analysis The binding operation uses the knowledge-storage endpoint `/openapi/skills/save_content/md`. The complete API key is sent not only in the authentication header, where it may legitimately be required, but also as both the `content` and `brand_name` fields. Credential validation does not require duplicating the secret into business-data fields. Because the selected endpoint is also used by `knowledge_tool.py` to store brand knowledge, the request may cause the API key to be retained as ordinary knowledge-base content, indexed data, application logs, analytics records, or audit records. This behavior exceeds the minimum privileges and data disclosure necessary for the declared binding function. It is also not disclosed in the Skill documentation, which only states that the key is bound and stored in a local `.env` file. ### Attack Path 1. A user invokes `bind_api_key.py --api-key ""`. 2. `request_bind_check()` places the complete secret in: - The `x-api-key` authentication header. - The `content` request field. - The `brand_name` request field. 3. The request is sent to a content-storage endpoint. 4. The remote servic ...[truncated 923 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
bind_api_key.py:79
Finding

API Keys Stored in Plaintext Files Without Restrictive Permissions

Content
View full analysis
None: """ Write a value to the .env file in the current Skill directory. Existing values with the same key are overwritten. """ env_data = load_env_file() env_data[key] = value content = "\n".join(f"{k}={v}" for k, v in env_data.items()) + "\n" ENV_FILE.write_text(content, encoding="utf-8") ``` `prompt_research.py` implements the same unrestricted write: ```python def save_env_value(key: str, value: str) -> None: env_data = load_env_file() env_data[key] = value content = "\n".join(f"{k}={v}" for k, v in env_data.items() if v) + "\n" ENV_FILE.write_text(content, encoding="utf-8") ``` It can persist a credential supplied directly through conversational input: ```python if state.get("awaiting_api_key"): if not looks_like_api_key(user_message): state["welcome_shown"] = True save_state(all_state) out_text(binding_prompt(include_note=True)) return save_env_value(ENV_KEY, user_message.strip()) state["awaiting_api_key"] = False ``` ```python if looks_like_api_key(user_message) and not has_api_key(state): save_env_value(ENV_KEY, user_message.strip()) state["awaiting_api_key"] = False save_state(all_state) out_text("Binding succeeded; the API Key was written to the shared configuration.") return ``` ### Technical Analysis The API key is written as plaintext into `.env` using `Path.write_text()`. The code does not: - Explicitly set the file mode to owner-only access, such as `0600`. - Verify that the destination is not a symbolic link. - Use an atomic temporary-file-and-rename operation. - Use an operating-system credential store. - Validate directly entered c ...[truncated 2394 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
prompt_research.py:44
Finding

Environment-Controlled API Base URL Can Redirect Authenticated Requests

Content
View full analysis
Dict[str, Any]: headers = { "x-api-key": api_key, "Content-Type": "application/json; charset=utf-8", } resp = requests.post( API_URL, headers=headers, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), timeout=120, ) ``` ### Technical Analysis The destination for question-research requests is controlled by the `GEO_API_BASE_URL` environment variable. No application-level validation restricts the URL to HTTPS or to the documented `api.aidso.com` hostname. The code unconditionally attaches the real AIDSO API key to requests sent to the configured URL. Therefore, anyone able to influence the Skill process environment can redirect the request to an arbitrary server and collect both the key and the research payload. A development endpoint override can be legitimate, but production credentials must not be attached to arbitrary destinations. The current implementation fails to establish that trust boundary. ### Attack Path 1. An attacker influences the environment used to launch the Skill, such as through a service definition, wrapper script, container configuration, CI variable, agent configuration, or inherited shell environment. 2. The attacker sets: ```bash GEO_API_BASE_URL=https://attacker.example ``` 3. A user invokes the question-research feature with a valid AIDSO API key available in the environment or `.env`. 4. `post_ques ...[truncated 922 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Dependency Version Is Not Fully Pinned

Content
View full analysis
=2.31.0 ``` ### Technical Analysis The dependency declaration specifies only a minimum version. Package installation can therefore select any later `requests` release available at installation time. This makes builds non-reproducible and allows unreviewed future versions, together with their transitive dependency graph, to enter the Skill environment. No malicious dependency was identified in the audited package, and `requests` is the expected correctly spelled package. The risk arises from the absence of a reviewed upper bound, exact lock, and integrity hashes rather than from a currently confirmed malicious release. ### Attack Path 1. The Skill is installed or rebuilt at a later date. 2. The package resolver selects a newer `requests` version than the version originally reviewed. 3. The selected release or one of its resolved transitive dependencies contains a vulnerability, malicious modification, or incompatible behavior. 4. The package is imported by each network-enabled Skill script. 5. Any harmful package initialization or request-handling behavior executes with the same local privileges as the Skill process. ### Impact Assessment A compromised dependency would execute in the Skill’s Python process and could potentially access: - The plaintext API key available through `.env` or the process environment. - User-provided brand, content, and question data. - Files accessible to the Skill process. - Network access available to the process. The precise impact depends on the behavior of the selected dependency release. No present compromise of the declared `requests` package was established during this audit. ]]>
Remediation
View remediation
``` 2. Pin transitive dependencies through a lock file generated by a controlled dependency-management process. 3. Require package hashes during installation, for example with `pip --require-hashes`. 4. Use a trusted package index and prevent fallback to unapproved repositories. 5. Run dependency vulnerability and provenance scanning in CI. 6. Update dependencies through reviewed pull requests with regression testing rather than resolving arbitrary future releases during deployment. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (63)

Tainted flow: 'headers' from os.getenv (line 119, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The code sends the API key directly to a remote endpoint in both the x-api-key header and the JSON body. Even though this may be intended as a key-validation workflow, transmitting a secret to an external service materially increases exposure if the endpoint is misconfigured, logged, compromised, or not clearly trusted by the user.

Content

Scanner excerpt · bind_api_key.py (reported line 125)May include surrounding context.

python
}

    try:
        response = requests.post(
            BIND_URL,
            headers=headers,
            data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),

Tainted flow: 'headers' from os.getenv (line 84, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · geo_content_tool.py (reported line 86)May include surrounding context.

python
def request_post(url: str, api_key: str, payload: Dict[str, Any], timeout: int = 180) -> Dict[str, Any]:
    headers = {"x-api-key": api_key, "Content-Type": "application/json"}
    try:
        response = requests.post(
            url,
            headers=headers,
            data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),

Tainted flow: 'headers' from os.getenv (line 107, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · geo_report_tool.py (reported line 113)May include surrounding context.

python
}

    try:
        response = requests.post(
            url,
            headers=headers,
            data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),

Tainted flow: 'headers' from os.getenv (line 40, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · knowledge_tool.py (reported line 42)May include surrounding context.

python
def request_post(url: str, api_key: str, payload: Dict[str, Any], timeout: int = 60) -> Dict[str, Any]:
    headers = {"x-api-key": api_key, "Content-Type": "application/json"}
    try:
        response = requests.post(url, headers=headers, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), timeout=timeout)
        try:
            data = response.json()
        except Exception:

Tainted flow: 'API_URL' from os.environ.get (line 48, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · prompt_research.py (reported line 562)May include surrounding context.

python
"Content-Type": "application/json; charset=utf-8",
    }

    resp = requests.post(
        API_URL,
        headers=headers,
        data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description presents a broader all-in-one GEO skill with multiple capabilities, but this code chunk is narrowly focused on GEO content production. It does not implement API key binding workflows, key verification, brand diagnosis reports, knowledge base operations, or question mining. Reading an API key from environment/.env and prompting the user to bind one is not equivalent to providing unified key binding/checking functionality. The implemented behavior is consistent with only one subset of the declared purpose, so the description overstates what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

该代码块的主要行为比较明确:1) 从环境变量或同目录 .env 读取 AIDSO_GEO_API_KEY;2) 调用 /get_questions 获取品牌问题列表;3) 调用 /band_report/md/v2 轮询生成报告 URL。虽然返回文案提示用户“绑定 api-key”,但实际没有实现绑定动作,也没有写入 .env、更新环境变量或单独检查 API Key 有效性的能力。更重要的是,声明中的‘品牌知识库’和‘GEO 内容生产’在代码中完全没有对应实现。因此,描述明显比实际实现更宽,属于能力声明与实际行为不符。不过代码确实覆盖了‘品牌诊断报告’和‘GEO 问题挖掘’这两部分。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a broad, integrated GEO skill with multiple functions: API key binding/checking, brand diagnosis reports, knowledge base operations, content production, and question mining. The supplied code chunk implements only one narrow capability: adding brand knowledge content through a single save_content API endpoint. It does not implement brand diagnosis, GEO content production, question mining, or a real API key bind/check feature beyond reading a key from environment variables or a .env file and returning an error if absent. This is a material scope mismatch because the actual behavior is substantially narrower than the declared purpose.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 32)May include surrounding context.

md
问题挖掘脚本 `prompt_research.py` 已改为读取统一 API Key 配置;`.state/prompt_research_bindings.json` 仅用于保存问题挖掘任务状态,不再保存 API Key。

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The script stores an API key in a .env file within the skill directory, which may be readable by other local users, accidentally committed to source control, or exposed through packaging/logging workflows. Local plaintext secret storage is a genuine credential-handling weakness even if common in developer tooling.

Content

Scanner excerpt · bind_api_key.py (reported line 28)May include surrounding context.

python
ENV_KEY = "AIDSO_GEO_API_KEY"
ENV_FILE = Path(__file__).resolve().parent / ".env"

BIND_URL = "https://api.aidso.com/openapi/skills/save_content/md"

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

This function writes the API key into a plaintext .env file without enforcing restrictive file permissions or validating that the location is safe. That can expose the credential through local file disclosure, backups, workspace sharing, or accidental repository inclusion.

Content

Scanner excerpt · bind_api_key.py (reported line 79)May include surrounding context.

python
def save_env_value(key: str, value: str) -> None:
    """
    写入当前 skill 目录下的 .env 文件。
    已存在同名 key 时覆盖。
    """
    env_data = load_env_file()

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 · bind_api_key.py (reported line 52)May include surrounding context.

python
def load_env_file() -> dict:
    """
    读取当前 skill 目录下的 .env 文件
    """
    result = {}

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 · bind_api_key.py (reported line 95)May include surrounding context.

python
def load_env_file() -> dict:
    """
    读取当前 skill 目录下的 .env 文件
    """
    result = {}

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 · check_api_key.py (reported line 32)May include surrounding context.

python
def load_env_file() -> dict:
    """
    读取当前 skill 目录下的 .env 文件
    """
    result = {}

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 · check_api_key.py (reported line 62)May include surrounding context.

python
def load_env_file() -> dict:
    """
    读取当前 skill 目录下的 .env 文件
    """
    result = {}

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 · check_api_key.py (reported line 77)May include surrounding context.

python
def load_env_file() -> dict:
    """
    读取当前 skill 目录下的 .env 文件
    """
    result = {}

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 · geo_report_tool.py (reported line 44)May include surrounding context.

python
def load_env_file() -> dict:
    """
    读取当前 skill 目录下的 .env 文件
    """
    result = {}

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 · geo_report_tool.py (reported line 78)May include surrounding context.

python
def load_env_file() -> dict:
    """
    读取当前 skill 目录下的 .env 文件
    """
    result = {}

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 · prompt_research.py (reported line 139)May include surrounding context.

python
def load_env_file() -> dict:
    """
    读取当前 skill 目录下的 .env 文件
    """
    result = {}

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 · bind_api_key.py (reported line 105)May include surrounding context.

python
import requests

ENV_KEY = "AIDSO_GEO_API_KEY"
ENV_FILE = Path(__file__).resolve().parent / ".env"
SAVE_URL = "https://api.aidso.com/openapi/skills/save_content/md"

def print_json(data: Dict[str, Any]) -> None:

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 · bind_api_key.py (reported line 207)May include surrounding context.

python
import requests

ENV_KEY = "AIDSO_GEO_API_KEY"
ENV_FILE = Path(__file__).resolve().parent / ".env"
SAVE_URL = "https://api.aidso.com/openapi/skills/save_content/md"

def print_json(data: Dict[str, Any]) -> None:

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 · check_api_key.py (reported line 23)May include surrounding context.

python
import requests

ENV_KEY = "AIDSO_GEO_API_KEY"
ENV_FILE = Path(__file__).resolve().parent / ".env"
SAVE_URL = "https://api.aidso.com/openapi/skills/save_content/md"

def print_json(data: Dict[str, Any]) -> None:

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 · check_api_key.py (reported line 84)May include surrounding context.

python
import requests

ENV_KEY = "AIDSO_GEO_API_KEY"
ENV_FILE = Path(__file__).resolve().parent / ".env"
SAVE_URL = "https://api.aidso.com/openapi/skills/save_content/md"

def print_json(data: Dict[str, Any]) -> None:

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 · geo_content_tool.py (reported line 17)May include surrounding context.

python
import requests

ENV_KEY = "AIDSO_GEO_API_KEY"
ENV_FILE = Path(__file__).resolve().parent / ".env"
SAVE_URL = "https://api.aidso.com/openapi/skills/save_content/md"

def print_json(data: Dict[str, Any]) -> None:

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 · geo_content_tool.py (reported line 79)May include surrounding context.

python
import requests

ENV_KEY = "AIDSO_GEO_API_KEY"
ENV_FILE = Path(__file__).resolve().parent / ".env"
SAVE_URL = "https://api.aidso.com/openapi/skills/save_content/md"

def print_json(data: Dict[str, Any]) -> None:

Static analysis

No suspicious patterns detected.