Back to skill

Security audit

Search Workflow

Security checks for vulnerabilities and agentic risk

Overview

This search skill mostly does what it claims, but it embeds a Tavily API key and can send user queries to an external service with broad trigger terms.

Install only after the hardcoded Tavily key is removed and rotated, the skill requires an explicit user-provided secret, and the manifest clearly discloses that queries are sent to Tavily and reports are written locally. Also consider narrowing the trigger keywords so routine search-related prompts do not automatically invoke external network calls.

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

Error
Location
scripts/search_workflow.py:12
Finding

Hardcoded Tavily API Credential

Content
View full analysis

Vulnerability Details

File Location: scripts/search_workflow.py, line 12
Vulnerability Type: Hardcoded secret
Risk Level: High

Vulnerable Code

python
TAVILY_API_KEY = os.getenv('TAVILY_API_KEY', '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')

The credential is subsequently transmitted in the authorization header:

python
def tavily_search(query, max_results=10):
    """Tavily search"""
    url = "https://api.tavily.com/search"
    headers = {"Authorization": f"Bearer {TAVILY_API_KEY}"}
    data = {
        "query": query,
        "search_depth": "advanced",
        "include_answer": True,
        "max_results": max_results
    }
    response = requests.post(url, json=data, headers=headers, timeout=30)
    return response.json()

Technical Analysis

The application retrieves TAVILY_API_KEY from the environment but supplies a usable-looking API credential as its default value. Consequently, distributing the skill also distributes that credential. Environment-variable support does not protect a secret when source code contains a fallback secret.

When the environment variable is absent, tavily_search() places the embedded credential in a bearer authorization header and sends it to the Tavily API. Any party able to inspect the package can extract the same credential without executing the script or possessing local privileges.

Attack Path

  1. An attacker downloads the published skill or otherwise obtains read access to its source package.
  2. The attacker opens scripts/search_workflow.py and copies the fallback Tavily token from line 12.
  3. The attacker constructs requests to the Tavily API using the token as a bearer credential.
  4. Tavily accepts requests under the credential owner's account if the exposed token remains active.
  5. The attacker consumes account quota or performs other operations permitted to that API credential until it is revoked or restricted.

Impact Assessment

Exploitation requires only read ...[truncated 620 chars]

Remediation
View remediation

Remediation Suggestions

  1. Revoke the exposed Tavily credential immediately and generate a replacement. Treat it as compromised even if no unauthorized use is currently known.
  2. Review Tavily usage and billing logs for unexpected requests, quota consumption, source addresses, or charges.
  3. Remove the fallback credential and require explicit secret configuration, for example:
python
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
if not TAVILY_API_KEY:
    raise RuntimeError("TAVILY_API_KEY must be configured")
  1. Supply the replacement through a secret manager or protected runtime environment variable. Do not place it in source files, documentation, examples, packaged artifacts, or committed configuration.
  2. If version-control history exists, purge the credential from prior commits and release artifacts. Rotation remains mandatory because history rewriting cannot invalidate previously copied secrets.
  3. Restrict the replacement credential to the minimum required API permissions and apply provider-supported quotas, spending limits, expiration, and source restrictions where available.
  4. Add automated secret scanning to pre-commit and CI workflows to prevent future credentials from being committed or published.
  5. Ensure logs and exception handlers do not print authorization headers or environment-variable values.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (15)

Tainted flow: 'headers' from os.getenv (line 18, 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 · scripts/search_workflow.py (reported line 25)May include surrounding context.

python
"include_answer": True,
        "max_results": max_results
    }
    response = requests.post(url, json=data, headers=headers, timeout=30)
    return response.json()

def process_results(results):

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented behavior does not match the detected implementation profile: it claims a broad multi-stage, multi-engine workflow, while analysis indicates only partial search behavior plus undisclosed local file output and a hardcoded default Tavily API key. This mismatch is dangerous because it can hide sensitive data handling, unreviewed outbound access, and credential exposure behind seemingly routine documentation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
78% confidence
Finding

The skill declares no explicit tool scope or permissions even though the associated capability profile indicates environment access, file writing, and network use. In an agent ecosystem, this creates an authorization and transparency gap: operators may approve or invoke the skill believing it is limited to harmless search behavior when it can access broader resources.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The user-facing instructions and examples are primarily presented in Chinese, but the file does not state that the skill is region- or language-specific, nor does it offer an opt-in or alternative language. This can violate language/locale policy because it effectively forces a specific language for use and comprehension.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The upload instructions tell the user to publish the skill to a remote service but do not clearly warn that publishing will package and transmit local skill contents off-host. That omission can lead users to upload files containing embedded secrets, internal metadata, unpublished code, or other sensitive local content without informed consent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger keywords include very broad generic terms like “搜索”, “查找”, “查询”, and “search”, which are likely to match many ordinary user requests unrelated to this specific workflow. In an agent environment, overly broad auto-triggering can cause the skill to activate unexpectedly, route queries through external search tools, and expand data exposure or tool use beyond what the user intended.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest advertises web search and full-page fetching but does not disclose that user queries and target URLs/content may be sent to external services. This is dangerous because users may unknowingly expose sensitive prompts, research topics, or retrieved page contents to third-party providers and remote websites.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest's natural-language description, workflow stage names, scenario descriptions, and output labels are entirely in Chinese, which indicates a fixed locale presentation. There is no explicit opt-in, language selection, or documented reason that the skill is intentionally restricted to Chinese-speaking users or a China-specific context.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger keywords are broad generic terms like 'search', '查询', and '资料', which can cause the skill to activate for many ordinary user requests. In a skill that performs networked search and page fetching, overbroad triggering can lead to unintended external requests, unnecessary data transmission, and accidental invocation of more powerful downstream tools than the user expected.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script embeds a default Tavily API key and automatically uses it for outbound requests. Hardcoded secrets are dangerous because they can be extracted from source control, reused by unauthorized parties, and may cause unintended billing, quota abuse, or account compromise; in a search skill, every user query is also transmitted to the external provider under that credential.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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/search_workflow.py (reported line 17)May include surrounding context.

python
def tavily_search(query, max_results=10):
    """Tavily 搜索"""
    url = "https://api.tavily.com/search"
    headers = {"Authorization": f"Bearer {TAVILY_API_KEY}"}
    data = {
        "query": query,

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The code sends user-supplied search queries and an API credential to an external third-party service. External transmission is expected for a search skill, but it is still security-relevant because sensitive queries may leave the local trust boundary and be processed or logged by the provider.

Content

Scanner excerpt · scripts/search_workflow.py (reported line 25)May include surrounding context.

python
"include_answer": True,
        "max_results": max_results
    }
    response = requests.post(url, json=data, headers=headers, timeout=30)
    return response.json()

def process_results(results):

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest describes a complete search workflow integrating tavily-search, web_search, web_fetch, and other search skills from query analysis to output. In practice, the implementation performs only a Tavily API call, simple deduplication, and saves a local report file, which is a narrower and somewhat different behavior than the described multi-skill workflow.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

Multiple docstrings and console messages are written only in Chinese, such as the module description and status output. This can violate language/locale policy when the skill forces a specific language without user opt-in or justification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The inline stage labels indicate a structured workflow including query analysis and deep-mode content extraction. However, the query analysis stage only prints status text, and the content extraction stage contains only a placeholder comment without any actual fetch or extraction behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.