Back to skill

Security audit

Clinical Trial Safety Signal / 临床试验安全信号专家

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly performs disclosed public safety-data retrieval, but it should be reviewed because routine requests send a stable machine-derived identifier that is not clearly disclosed to users.

Install only if you are comfortable sending public drug/event queries plus a stable hashed machine identifier to the publisher-operated Coze endpoints. Avoid confidential inputs, review any CT_SEARCH_ENDPOINT or CT_SEARCH_ENDPOINT_STREAM environment overrides before use, and only approve bug-report submission after inspecting the displayed report.

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

T09 · Insecure Skill Coding Practices

Warning
Location
adapters/coze_dispatch.py:397
Finding

Persistent hardware-derived device fingerprint transmitted during routine retrieval

Content
View full analysis

Vulnerability Details

File Location: scripts/hardware_id.py:35-79, 88-90; adapters/nmpa_coze.py:148-154, 351-359; adapters/coze_dispatch.py:397-443
Vulnerability Type: Undisclosed persistent device tracking
Risk Level: Medium

Relevant Code

python
# scripts/hardware_id.py:35-79
if sys.platform.startswith("win"):
    try:
        out = subprocess.check_output(
            [r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe",
             "-NoProfile", "-Command",
             "(Get-CimInstance Win32_ComputerSystemProduct).UUID"],
            stderr=subprocess.DEVNULL, text=True, timeout=10)
        s = out.strip()
        if s and s.upper() not in ("UUID", "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"):
            return "win:smbios:" + s
    except Exception:
        pass
    try:
        import winreg
        with winreg.OpenKey(
            winreg.HKEY_LOCAL_MACHINE,
            r"SOFTWARE\Microsoft\Cryptography",
        ) as k:
            return "win:machineguid:" + winreg.QueryValueEx(k, "MachineGuid")[0]
    except Exception:
        pass
elif sys.platform == "darwin":
    try:
        out = subprocess.check_output(
            ["ioreg", "-rd1", "-c", "IOPlatformExpertDevice"],
            stderr=subprocess.DEVNULL, text=True, timeout=10)
        for line in out.splitlines():
            if "IOPlatformUUID" in line:
                parts = line.split('"')
                if len(parts) >= 4 and parts[3].strip():
                    return "mac:platformuuid:" + parts[3].strip()
    except Exception:
        pass
else:
    for p in ("/etc/machine-id", "/var/lib/dbus/machine-id"):
        try:
            with open(p, encoding="utf-8") as f:
                s = f.read().strip()
            if s:
                return "linux:machine-id:" + s
        except Exception:
            pass
python
# scripts/hardware_id.py:88-9
...[truncated 4201 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove query_origin from ordinary retrieval payloads unless a stable device identifier is strictly necessary.
  2. For rate limiting, prefer server-observed, short-lived signals or an unlinkable random identifier that rotates regularly.
  3. If installation-level identification is required, generate a cryptographically random identifier rather than deriving it from SMBIOS UUID, MachineGuid, platform UUID, or machine-id.
  4. Make telemetry opt-in and obtain explicit informed consent before collecting it.
  5. Clearly disclose the exact field, source, purpose, destination, retention period, and correlation scope in SKILL.md and user-facing documentation.
  6. Provide a supported option to disable telemetry without disabling the core retrieval capability.
  7. Separate telemetry authorization from endpoint allow-listing. An endpoint being allow-listed should not implicitly authorize collection of persistent device identifiers.
  8. Add tests asserting that default retrieval payloads contain only documented public query fields and do not include hardware-derived identifiers.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (129)

Tainted flow: 'req' from os.environ.get (line 335, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
91% confidence
Finding

The request target is derived from environment-controlled endpoint configuration and then used directly in urlopen. If an attacker can influence CT_SEARCH_ENDPOINT_STREAM or related config, they can redirect sensitive outbound traffic, including bearer tokens and query contents, to an attacker-controlled host, creating SSRF/exfiltration risk.

Content

Scanner excerpt · adapters/coze_dispatch.py (reported line 337)May include surrounding context.

python
"""单次 /stream_run 请求 + SSE 解析;返回 workflow_end.output(dict|list)或 None,异常上抛。"""
    req = urllib.request.Request(CT_SEARCH_ENDPOINT_STREAM, data=body,
                                 headers=_stream_headers(), method="POST")
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        return _parse_stream(resp)

Tainted flow: 'req2' from os.environ.get (line 457, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
93% confidence
Finding

The fallback /run request also uses an environment-derived endpoint directly in urlopen, so the same endpoint-injection risk exists on the non-stream path. Because this code sends sanitized but still potentially sensitive medical search terms plus Authorization headers, a malicious endpoint could capture credentials and user query data.

Content

Scanner excerpt · adapters/coze_dispatch.py (reported line 459)May include surrounding context.

python
_acquire_rate_limit()
        req2 = urllib.request.Request(CT_SEARCH_ENDPOINT, data=body,
                                      headers=_stream_headers(), method="POST")
        with urllib.request.urlopen(req2, timeout=timeout) as resp2:
            data = json.loads(resp2.read().decode("utf-8"))
        result = _parse_run_response(data, source)
        _maybe_write_out(out, result)

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

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

md
��全信号,计算 disproportionality(PRR / ROR / IC / EBGM,含 95% CI)与安全信号评分(0–100,T1–T4)。数据源:FDA FAERS(openFDA drug/event.json)、FDA 标签(drug/label.json)、中国 NMPA 药物警戒通报(cdr-adr.org.cn)、DailyMed 说明书、RxClass MED-RT、openFDA 召回执法、香港 ADR 警报。仅公开数据,零保密输入。"
license: MIT
description: "Screen drug–event safety signals via disproportionality analysis (PRR / ROR / IC / EBGM with 95% CIs) on FDA FAERS, with Safety Signal Score (0–100, T1–T4). Sources: FDA FAERS (openFDA drug/event.json), FDA Label (drug/label.json), China NMPA PV bulletins (cdr-adr.org.cn), DailyMed SPL, RxClass MED-RT, openFDA enforcement recalls, Hong Kong ADR Alerts. Public data only; zero confidential input. / 基于 FDA FAERS 筛查药物-事件安全信号,计算 disproportionality(PRR / ROR / IC / EBGM,含 95% CI)与安全信号评分(0–100,T1–T4)。数据源:FDA F

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
dual case reports (HARD_CAP 10000) for age/country stats. Signal detection via `ct_safety.py`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
dual case reports (HARD_CAP 10000) for age/country stats. Signal detection via `ct_safety.py`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- CN-PV is an in-skill qualitative add-on, not a chain target. Units: `references/units.md`. Changelog: `CHANGELOG.md`.

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

md
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_faers.py (reported line 51)May include surrounding context.

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_faers.py (reported line 57)May include surrounding context.

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_faers.py (reported line 61)May include surrounding context.

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_faers.py (reported line 364)May include surrounding context.

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_fda_label.py (reported line 33)May include surrounding context.

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_fda_label.py (reported line 39)May include surrounding context.

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_fda_label.py (reported line 43)May include surrounding context.

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_fda_label.py (reported line 255)May include surrounding context.

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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

python
BASE = "https://api.fda.gov/drug/label.json"
_RETRY_STATUSES = {404, 429, 500, 502, 503, 504}

# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

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 · adapters/fetch_faers.py (reported line 54)May include surrounding context.

python
# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

# OpenFDA key obfuscation (ct-base §5, private-credential best practice).
# A skill-root .env may store either a plaintext key OR an `obf:`-prefixed

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 · adapters/fetch_fda_label.py (reported line 36)May include surrounding context.

python
# Skill root (parent of the scripts/ dir). Used to locate a local .env that
# holds the openFDA key WITHOUT shipping it inside the published package.
_SKILL_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_DOTENV = os.path.join(_SKILL_ROOT, ".env")

# OpenFDA key obfuscation (ct-base §5, private-credential best practice).
# A skill-root .env may store either a plaintext key OR an `obf:`-prefixed

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · adapters/nmpa_coze.py (reported line 74)May include surrounding context.

python
ge = None
    _i18n_current_lang = None

# ── ct-base §5 公用凭据:与 ct-registry 同一份统一端点 token ──────────────
# XOR key 与 ct-registry adapters/endpoint_token.py 保持一致以兼容同一 blob。
OBFUSCATION_KEY = b"ct-registry-extsvc-obf-v1-9c4d2a"

_EMBEDDED_COZE_UNIFIED = (
    "Bg1nGgcgCho7GzN-MAI9QjgKZBwrC1kGa25wVX0Jfxk5Hk5HKyM_HjgmM0UoPDUHOCdKGDsPHB5oR1IbeDBnVSwwRkc8VTgKOTYRRigBPkpYBlQlEgUeO1hiUClbAHozFBdXHRMrWzUDEyoYDxpHAxovQCEXL0QBWHRhNV8tWBEBPUE4MQYCQjYgPWBWGkclIDdDCBsrHhJod30tZikAGRM5RxYSBQMbRStKfBwxGEMFKkA5VgVuPwdifSpMKXYoUTpHFVYpAxBBPSpaDBkjNUYqRwAaKFcRAGBtNgYrdjhXOG44HwM-Oh09EGcfGzMfGzlAOlQqVE9ZTn4IQT0AWFUufkcPBQBKRxBKZxcaM0oeOWtWEjxqIERJfg8EAWFYEy5pHVYpAypFPS1KVzcgIkYuaQQYKXkzS2BtJgQtWxYKFx44Dy4DHB0TLhgMGkclAzlrVgoCdSRedQslXj0ANxkXHEtVBVsHGBAVFBUiMBxFLUc2USt5HUZgQzoHKXYoUDt5FVcpLSIMOxcdSzVEEEA8WjUAKF0YAkp2M1M3UwIKHwAdCAk6PhAxPmYsPx8aACp9PiQNSkZoTHc2TR58BS0HFCgCViMEEhhMXUhARitAElkXGgh4FEtlVVNkVn84BC0cFCEoOio6

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This line states that all Chinese body text in SKILL.md was translated to English to comply with a rule that the body must be entirely English. That is a natural-language locale policy constraint that forces a specific language without indicating user choice or a narrowly justified regional limitation.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This line explicitly describes a human-language trigger phrase that causes the system to skip the preview and proceed to run. Even though it is framed as a confirmation UX improvement, the semantic effect is to let a user steer execution through a special phrase, which is a natural-language action trigger rather than a normal parameterized control.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Automatically approving a bug-report endpoint creates a path for data to leave the environment without per-request user review. Even if the payload is intended to be an 11-key allowlisted envelope, changelog text shows the endpoint is pre-approved and uses an embedded public token, so accidental inclusion of sensitive contents or abuse of the reporting path becomes more plausible.

Content

Scanner excerpt · CHANGELOG.md (reported line 392)May include surrounding context.

md
### Added / bug report 接入(ct-base §20.3 + §20.3.7)
- **`adapters/bug_report.py` 补齐 §20.3.7 三函数**:新增 `confirm_thanks()`(发送成功固定感谢)、`parse_history()`(history 字段→dict 容错)、`build_followup()`(依据 resultstr 生成 2.2 已修复 / 2.3 未修复通知)。此前该文件仅含 §20.3.1–§20.3.5 基础函数,缺 §20.3.7 历史回执能力。
- **`_MSGS` 字典补齐**:新增 `thank_zh/en`、`done_zh/en`、`pending_zh/en` 六个键,供上述三函数调用。
- **新增 `adapters/config.json`**:`auto_approve_endpoints` 列入 `https://ct-bugreport.coze.site/run`,满足 §20.3.5(每个技能须将统一 bug-report 端点列入自动批准白名单)。此前 ct-safety 缺失 config.json。
- **README 出站披露补齐**:新增 "Bug-report endpoint disclosure (ct-base §5 / §20.3)" 段落,披露 11-key 白名单信封发送至 `https://ct-bugreport.coze.site/run`,与 SKILL.md §20.3 章节对齐。
- **已合规项确认**:`bug_report.py` 的 `DEFAULT_ENDPOINT` 已为 `https://ct-bugreport.coze.site/run` 且含嵌入式公共 token(§5);SKILL.md Bug Reporting 章节(双阶段确认 + 11-key 白名单 + 出站披露)此前已就位(2026-08-21)。

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The examples teach the agent to treat unconstrained natural-language medical questions as execution triggers without clear boundaries. Because the skill performs outbound retrieval through a remote endpoint, this increases the risk of overbroad activation, accidental data transmission, and confusion about when the tool is merely discussing versus actually running.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README uses very broad natural-language trigger phrases for activation, such as ordinary conversational requests. In an agent setting, vague triggers can cause accidental invocation or unintended execution of networked data-retrieval actions when the user did not clearly intend to run this skill.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.