Back to skill

Security audit

标讯猎手 BidHunter

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly fits its bid-monitoring purpose, but it needs Review because remote bid data can be injected into local HTML reports and the local rule editor can be changed by cross-site browser requests.

Install only if you are comfortable reviewing a security-sensitive procurement automation tool. Use local-only and non-AI modes unless tender data may be sent to your configured model provider, avoid opening generated HTML reports from untrusted/custom feeds until HTML escaping is fixed, run the rule editor only briefly, and close it before browsing unrelated sites.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/report_html.py:75
Finding

Stored HTML and Script Injection Through Remote Announcement Data

Content
View full analysis

Vulnerability Details

File Location: scripts/report_html.py:75-117
Vulnerability Type: Stored HTML injection / local report XSS
Risk Level: High

Complete Code Snippet

python
title = item.get("title", "")
rid = item.get("id", "")
url = item.get("url", "")
reason = item.get("reason", "")
entity = item.get("assigned_entity_name", item.get("assigned_entity", ""))
caps = item.get("matched_capabilities", [])
region_info = item.get("region_info", {})
is_priority = region_info.get("is_priority", False)
region = region_info.get("region", "")
source = item.get("source", "")
publish_time = item.get("publish_time", "")

priority_badge = '<span class="badge priority">重点</span>' if is_priority else ""
region_badge = f'<span class="badge region">{region}</span>' if region else ""
source_badge = f'<span class="badge source">{source}</span>' if source else ""
entity_badge = f'<span class="badge entity">{entity}</span>' if entity else ""
score_badge = ""
if verdict == "investable":
    sc = item.get("score")
    lvl = item.get("score_level", "")
    if isinstance(sc, int):
        score_badge = f'<span class="badge score">🔥 {lvl} {sc}</span>'
caps_html = '<div class="caps">' + "".join(
    f'<span class="cap-tag">{c}</span>' for c in caps
) + '</div>' if caps else ""
link_html = (
    f'<a href="{url}" target="_blank" class="detail-link">查看详情</a>'
    if url else ""
)

items_html += f"""
<div class="item-card" style="border-left-color: {style['color']}; background: {style['bg']}">
    <div class="item-header">
        <span class="seq-num">#{seq}</span>
        <span class="verdict-badge" style="background: {style['color']}; color: white;">{style['label']}</span>
        {priority_badge}{region_badge}{source_badge}{entity_badge}{score_badge}
    </div>
    <div class="item-title">{title}</div>
    <div class="item-reason">{reason}</div>
    {caps_html}
    <div class="item-meta">
        <span>ID: {rid}</span>
        {f'<span>发布时间: {publish_time}</span
...[truncated 3590 chars]
Remediation
View remediation

Remediation Suggestions

  1. Encode every untrusted value according to its output context:
    • Apply html.escape(value, quote=True) to text and attribute values.
    • Do not reuse values encoded for text nodes in URL or JavaScript contexts.
  2. Validate links before rendering:
    • Parse URLs with urllib.parse.urlsplit.
    • Allow only explicitly supported schemes such as https and, if required, http.
    • Reject control characters, protocol-relative URLs where inappropriate, and schemes such as javascript, data, and file.
  3. Prefer structured rendering helpers rather than manually concatenating HTML strings.
  4. Add a restrictive Content Security Policy to the generated report, for example:
    html
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'none'; style-src 'unsafe-inline'; img-src data: https:; base-uri 'none'; form-action 'none'">
    
  5. Add rel="noopener noreferrer" to links using target="_blank".
  6. Add regression tests containing hostile values in every remotely sourced field, including:
    • HTML elements and event-handler attributes.
    • Quotes that attempt to escape href.
    • javascript: and data: URLs.
    • Encoded and mixed-case unsafe schemes.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rule_editor.py:246
Finding

Cross-Site Requests Can Replace the Active Qualification Rules

Content
View full analysis

Vulnerability Details

File Location: scripts/rule_editor.py:246-287
Vulnerability Type: Cross-Site Request Forgery against a localhost configuration service
Risk Level: Medium

Complete Code Snippet

python
class Handler(BaseHTTPRequestHandler):
    def _send(self, code, obj):
        self.send_response(200)
        self.send_header("Content-Type", "application/json; charset=utf-8")
        self.end_headers()
        self.wfile.write(json.dumps(obj, ensure_ascii=False).encode("utf-8"))

    def _send_html(self, html):
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.end_headers()
        self.wfile.write(html.encode("utf-8"))

    def do_GET(self):
        u = urlparse(self.path)
        if u.path == "/" or u.path == "/index.html":
            try:
                rules = load_rules(RULES_PATH)
            except Exception as e:
                rules = {
                    "entities": {},
                    "red_alerts": [],
                    "region_priority": {"high": []},
                    "_note": "load failed: " + str(e),
                }
            html = PAGE.replace(
                "{{RULES_JSON}}",
                json.dumps(rules, ensure_ascii=False),
            )
            self._send_html(html)
        elif u.path == "/api/templates":
            self._send(200, list(TEMPLATES.keys()))
        else:
            self.send_error(404)

    def do_POST(self):
        u = urlparse(self.path)
        length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(length).decode("utf-8") if length else "{}"
        try:
            data = json.loads(body)
        except Exception:
            data = {}

        if u.path == "/api/rules":
            try:
                save_rules(RULES_PATH, data)
                self._send(
                    200,
                    {"ok": True, "msg": "已写入 qual_rules.json(含备份)"},
                )
    
...[truncated 3246 chars]
Remediation
View remediation

Remediation Suggestions

  1. Generate a cryptographically random token at every editor launch:
    python
    import secrets
    CSRF_TOKEN = secrets.token_urlsafe(32)
    
    Embed it into the editor page and require it in a custom header or request body for every state-changing endpoint.
  2. Reject requests before processing their bodies unless:
    • Origin exactly matches the editor origin.
    • Host is an expected loopback host and port.
    • The CSRF token is valid.
    • Content-Type is exactly an accepted JSON media type.
  3. Use constant-time token comparison with secrets.compare_digest.
  4. Consider binding to a randomized high port and opening a URL containing an unguessable capability token.
  5. Apply the same protection to /api/validate and /api/test, because they create predictable temporary files and invoke local processing.
  6. Set defensive response headers, including:
    • Content-Security-Policy
    • X-Content-Type-Options: nosniff
    • Referrer-Policy: no-referrer
    • Cache-Control: no-store
  7. Honor the status argument in _send() rather than always returning HTTP 200.
  8. Validate the submitted rule schema before replacing the active file, and reject unexpected fields, excessive nesting, or oversized request bodies.
Vulnerability Patterns
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (101)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents local telemetry/event tracking written to a user config path, but that behavior is not surfaced in the high-level declared purpose. Undisclosed telemetry, even if local-only, is security-relevant because it may record sensitive procurement workflow metadata and create privacy or data-retention risk users did not knowingly accept.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/init_wizard.py (reported line 140)May include surrounding context.

python
rules["_initialized"] = True
    rules["_initialized_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    rules["description"] = f"{data['entity']} 资质规则(由 init 生成)"
    return rules


def _default_base():

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/init_wizard.py (reported line 194)May include surrounding context.

python
rules["_initialized"] = True
    rules["_initialized_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    rules["description"] = f"{data['entity']} 资质规则(由 init 生成)"
    return rules


def _default_base():

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/init_wizard.py (reported line 212)May include surrounding context.

python
rules["_initialized"] = True
    rules["_initialized_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    rules["description"] = f"{data['entity']} 资质规则(由 init 生成)"
    return rules


def _default_base():

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/init_wizard.py (reported line 213)May include surrounding context.

python
rules["_initialized"] = True
    rules["_initialized_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    rules["description"] = f"{data['entity']} 资质规则(由 init 生成)"
    return rules


def _default_base():

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/rule_editor.py (reported line 202)May include surrounding context.

python
RULES.red_alerts=document.getElementById('red_alerts').value.split(/[,\n]/).map(s=>s.trim()).filter(Boolean);
  RULES.region_priority=RULES.region_priority||{{}};
  RULES.region_priority.high=document.getElementById('region_high').value.split(/[,\n]/).map(s=>s.trim()).filter(Boolean);
  return RULES;
}}
function loadTpls(){{
  fetch('/api/templates').then(r=>r.json()).then(ts=>{{

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The configuration states that the skill does not send bid documents or sensitive content to third parties, yet it also declares an external AI API for document-related analysis. In a bidding/procurement context, bid documents may contain confidential commercial, legal, pricing, or personal data, so this contradiction can cause unsafe operator assumptions and unintentional external disclosure.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises and documents capabilities that read/write local files, invoke shell commands, access environment/config files, and perform network-facing actions, but the manifest does not declare any explicit tool scope or permission boundaries. This increases the risk of over-privileged execution or accidental exposure of sensitive local data because reviewers and runtime policy engines cannot clearly constrain what the skill is allowed to do.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Embedding a long list of broad trigger phrases directly in the manifest description increases ambiguous activation and makes policy review harder. Because the skill can touch local files and invoke operational workflows, overbroad triggers raise the chance of unintended execution and user confusion about when the skill should run.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger list includes very broad natural-language phrases, increasing the chance of accidental invocation in unrelated conversations. In a skill with file, shell, and network-adjacent capabilities, unintended activation can cause surprise document processing, local data access, or external actions that the user did not mean to initiate.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.