Back to skill

Security audit

Deep Research Pipeline

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate deep-research helper, but it needs Review because it can fetch arbitrary URLs and send research data and API keys to configurable LLM endpoints without strong destination controls.

Install only if you are comfortable with the skill making outbound web, GitHub, documentation, and LLM-provider requests. Avoid confidential research topics unless you control the provider endpoint and local workspace, prefer HTTPS trusted endpoints, review any custom LLM base URL carefully, and treat checkpoints/output files as potentially sensitive retained data.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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/research_sources.py:46
Finding

Unrestricted URL Fetching Enables Server-Side Request Forgery

Content
View full analysis
Optional[str]: """Fetch a URL and return text content. Returns None on failure.""" try: req = urllib.request.Request( url, headers={"User-Agent": "Mozilla/5.0 (compatible; ResearchBot/1.0)"}, ) with urllib.request.urlopen(req, timeout=timeout) as resp: content_type = resp.headers.get("Content-Type", "") if "text" not in content_type and "json" not in content_type: return None return resp.read(max_chars).decode(errors="replace") except Exception: return None ``` Direct document URLs are passed to this helper without destination validation: ```python def search(self, query: str, limit: int = 5) -> list[dict]: """Fetch documentation from a URL or search for relevant docs. If query looks like a URL, fetch it directly. Otherwise, try to discover relevant documentation pages. """ # If query is a URL, fetch directly if query.startswith("http://") or query.startswith("https://"): return self._fetch_doc_page(query) ``` The context expander independently implements the same unsafe behavior: ```python def _fetch_url(url: str, max_chars: int = 30000) -> Optional[str]: """Fetch a URL and return text content.""" try: req = urllib.request.Request( url, headers={"User-Agent": "Mozilla/5.0 (compatible; ResearchBot/1.0)"}, ) with urllib.request.urlopen(req, timeout=15) as resp: content_type = resp.headers.get("Content-Type", "") if "t ...[truncated 2714 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Warning
Location
scripts/chunk_selector.py:97
Finding

Untrusted Web Content Can Manipulate LLM Research Decisions and Final Reports

Content
View full analysis
list[dict]: """Score a batch of chunks using LLM.""" system = ( "You are a research relevance scorer. Score each chunk's relevance " "to the research question on a scale of 0.0 to 1.0.\n\n" "Scoring criteria:\n" "- 1.0: Directly answers or is essential context for the question\n" "- 0.8: Highly relevant supporting information\n" "- 0.6: Somewhat relevant but tangential\n" "- 0.4: Loosely related, minor utility\n" "- 0.2: Barely related\n" "- 0.0: Completely irrelevant\n\n" 'Output ONLY a JSON array. Each element: {"index": N, "score": 0.X, ' '"reason": "one sentence"}. Use the same index numbers as input.' ) # Build numbered list numbered = [] for i, chunk in enumerate(batch): numbered.append( f"[{i}] {chunk.get('title', 'Untitled')} ({chunk.get('url', 'unknown')})\n" f"{chunk.get('content', '')[:2000]}" ) prompt = ( f"Research question: {question}\n\n" f"Chunks to score:\n{chr(10).join(numbered)}\n\n" "Score each chunk. Output JSON array only." ) try: response = _call_glm(prompt, system, max_tokens=4096, temperature=0.1, api_key=api_key) response = response.strip() if response.startswith("```"): response = response.split("\n", 1)[1].rsplit("```", 1)[0].strip() scores = json.loads(response) if not isinstance(scores, list): ...[truncated 3727 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/llm_client.py:32
Finding

Custom LLM Endpoints Can Receive API Credentials and Research Data over Unsafe Destinations

Content
View full analysis
tuple[str, str, str]: """Resolve API key, base URL, and model from environment.""" # Universal overrides (highest priority) api_key = os.environ.get("LLM_API_KEY", "") base_url = os.environ.get("LLM_API_BASE", "") model = os.environ.get("LLM_MODEL", "") if api_key and base_url: return api_key, base_url.rstrip("/"), model or "gpt-4o-mini" # OpenAI-compatible (standard) openai_key = os.environ.get("OPENAI_API_KEY", "") openai_base = os.environ.get("OPENAI_API_BASE", "") or os.environ.get("OPENAI_BASE_URL", "") if openai_key: base = openai_base.rstrip("/") if openai_base else "https://api.openai.com/v1" return openai_key, base, model or "gpt-4o-mini" # Z.AI GLM (legacy) zai_key = os.environ.get("ZAI_API_KEY", "") zai_endpoint = os.environ.get("ZAI_API_ENDPOINT", "https://api.z.ai/api/coding/paas/v4") glm_model = os.environ.get("GLM_MODEL", "glm-5-turbo") if zai_key: return zai_key, zai_endpoint.rstrip("/"), model or glm_model raise RuntimeError( "No LLM API key configured. Set one of: " "LLM_API_KEY, OPENAI_API_KEY, or ZAI_API_KEY" ) ``` The resolved key is sent to the unrestricted endpoint: ```python resolved_key, resolved_base, resolved_model = _resolve_config() key = api_key or resolved_key base = (base_url or resolved_base).rstrip("/") mdl = model or resolved_model messages = [] if system: messages.append({"role": "system", "content": system}) messages.append({"role": "user", "content": prompt}) payload = { "model": mdl, "messages": messages, "max_tokens": max_tokens, "temperature": temperature, } data = json.dumps(payload).encode() end ...[truncated 2393 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (39)

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

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The request destination is derived from environment-controlled base URL values and then used in a network call with an Authorization bearer token. If an attacker can influence environment variables in the agent runtime, they can redirect prompts and API credentials to an attacker-controlled endpoint, causing credential exfiltration and disclosure of potentially sensitive research data.

Content

Scanner excerpt · scripts/llm_client.py (reported line 122)May include surrounding context.

python
},
    )
    try:
        with urllib.request.urlopen(req, timeout=120) as resp:
            result = json.loads(resp.read())
            return result["choices"][0]["message"]["content"]
    except urllib.error.HTTPError as e:

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

To the extent this finding highlights undeclared external API access, it overlaps with a real security issue: the skill advertises use of provider endpoints via environment variables without explicit scope declaration or clear disclosure boundaries. Misdescribed or underdeclared networked behavior can cause users to send sensitive prompts or retrieved data to third-party services without informed consent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

To the extent this finding highlights undeclared external API access, it overlaps with a real security issue: the skill advertises use of provider endpoints via environment variables without explicit scope declaration or clear disclosure boundaries. Misdescribed or underdeclared networked behavior can cause users to send sensitive prompts or retrieved data to third-party services without informed consent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

To the extent this finding highlights undeclared external API access, it overlaps with a real security issue: the skill advertises use of provider endpoints via environment variables without explicit scope declaration or clear disclosure boundaries. Misdescribed or underdeclared networked behavior can cause users to send sensitive prompts or retrieved data to third-party services without informed consent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

To the extent this finding highlights undeclared external API access, it overlaps with a real security issue: the skill advertises use of provider endpoints via environment variables without explicit scope declaration or clear disclosure boundaries. Misdescribed or underdeclared networked behavior can cause users to send sensitive prompts or retrieved data to third-party services without informed consent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

To the extent this finding highlights undeclared external API access, it overlaps with a real security issue: the skill advertises use of provider endpoints via environment variables without explicit scope declaration or clear disclosure boundaries. Misdescribed or underdeclared networked behavior can cause users to send sensitive prompts or retrieved data to third-party services without informed consent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

To the extent this finding highlights undeclared external API access, it overlaps with a real security issue: the skill advertises use of provider endpoints via environment variables without explicit scope declaration or clear disclosure boundaries. Misdescribed or underdeclared networked behavior can cause users to send sensitive prompts or retrieved data to third-party services without informed consent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

To the extent this finding highlights undeclared external API access, it overlaps with a real security issue: the skill advertises use of provider endpoints via environment variables without explicit scope declaration or clear disclosure boundaries. Misdescribed or underdeclared networked behavior can cause users to send sensitive prompts or retrieved data to third-party services without informed consent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

To the extent this finding highlights undeclared external API access, it overlaps with a real security issue: the skill advertises use of provider endpoints via environment variables without explicit scope declaration or clear disclosure boundaries. Misdescribed or underdeclared networked behavior can cause users to send sensitive prompts or retrieved data to third-party services without informed consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill documentation describes sending user questions, generated queries, page content, and selected chunks through web search, GitHub, documentation fetchers, and LLM-based scoring/selection, but it does not clearly warn that this data may be transmitted to third-party services. In a research skill, users may submit confidential topics or internal text, so omission of this warning creates a real privacy and data-handling risk.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 · DOCS.md (reported line 451)May include surrounding context.

bash
# Universal OpenAI-compatible provider
export LLM_API_KEY="your-key-here"
export LLM_API_BASE="https://api.example.com/v1"
export LLM_MODEL="your-model"

# Or OpenAI-compatible env names

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 · DOCS.md (reported line 456)May include surrounding context.

bash
# Universal OpenAI-compatible provider
export LLM_API_KEY="your-key-here"
export LLM_API_BASE="https://api.example.com/v1"
export LLM_MODEL="your-model"

# Or OpenAI-compatible env names

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents capabilities that require network access, environment-variable access, and local file writes, but it declares no explicit tool scope or permissions. That creates a transparency and governance gap: operators cannot easily constrain or review what the skill is allowed to do, increasing the chance of unintended data exposure or filesystem modification when the skill is run.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill encourages web fetching, LLM-provider configuration, and writing reports/checkpoints locally, but it does not clearly disclose that user prompts, retrieved source content, and generated outputs may be transmitted to third-party providers and persisted on disk. This can lead to accidental leakage of proprietary, personal, or regulated data during research workflows.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The skill explicitly supports sending data to external OpenAI-compatible endpoints via environment-configured URLs. External transmission is not inherently malicious in a research skill, but it is security-relevant because sensitive prompts, fetched content, or intermediate findings may be disclosed to third-party services.

Content

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

md
# Optional: configure any OpenAI-compatible provider
export LLM_API_KEY="your-key"
export LLM_API_BASE="https://api.example.com/v1"
export LLM_MODEL="your-model"

# Or use OpenAI-compatible env names

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This is another instance of documented outbound transmission to external provider infrastructure. In context, the risk is amplified because the skill is designed for broad research ingestion and synthesis, so users may pass large volumes of unreviewed or sensitive material through those endpoints.

Content

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

md
# Or use OpenAI-compatible env names
export OPENAI_API_KEY="your-key"
export OPENAI_BASE_URL="https://api.example.com/v1"

# Run a report
python3 scripts/research_pipeline.py \

Session Persistence

Medium
Category
Rogue Agent
Confidence
91% confidence
Finding

The skill instructs creation of persistent research directories and storage of plans, reflections, outputs, reviews, provenance, and checkpoints. Persistent session artifacts can retain sensitive queries, fetched source content, and generated analysis beyond the immediate task, creating confidentiality and data-retention risk if the workspace is shared or insufficiently protected.

Content

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

md
## Workflow (Orchestrated Mode)

### Phase 1: Planning
- Analyze question, create slug, make `memory/research/<slug>/` directory
- Generate research plan with dimensions and questions
- Save to `plan.md`

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
## Integrity Commandments
1. Never fabricate a source — no URL = don't mention it
2. Never claim existence without checking
3. Never extrapolate unread details
4. Read before summarizing
5. No fake certainty — never say "verified" unless checked

Ssd 4

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Untrusted chunk text is interpolated directly into the prompt sent to the LLM, so a malicious or crafted source document can include prompt-injection content like instructions to ignore scoring criteria, skew scores, or emit malformed output. In this skill, chunk selection is a trust boundary for downstream synthesis, so poisoned scoring can cause relevant evidence to be dropped or adversarial content to be preferentially retained.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script sends the research question and chunk contents to an external LLM service via _call_glm without any visible consent, warning, redaction, or data-classification check. In a deep-research skill, retrieved chunks may include sensitive internal notes, proprietary material, or personal data, so silent exfiltration to a third-party model is a real privacy and compliance risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code automatically fetches arbitrary HTTP(S) URLs from chunk metadata without any user-facing disclosure or consent. In a deep-research skill, that means running the tool can trigger outbound requests to third-party sites, leaking the operator's IP/user-agent and potentially contacting attacker-controlled endpoints if upstream chunk data is untrusted.

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

python
openai_key = os.environ.get("OPENAI_API_KEY", "")
    openai_base = os.environ.get("OPENAI_API_BASE", "") or os.environ.get("OPENAI_BASE_URL", "")
    if openai_key:
        base = openai_base.rstrip("/") if openai_base else "https://api.openai.com/v1"
        return openai_key, base, model or "gpt-4o-mini"

    # Z.AI GLM (legacy)

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

md
# Z.AI GLM (legacy)
    zai_key = os.environ.get("ZAI_API_KEY", "")
    zai_endpoint = os.environ.get("ZAI_API_ENDPOINT", "https://api.z.ai/api/coding/paas/v4")
    glm_model = os.environ.get("GLM_MODEL", "glm-5-turbo")
    if zai_key:
        return zai_key, zai_endpoint.rstrip("/"), model or glm_model

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

python
# Z.AI GLM (legacy)
    zai_key = os.environ.get("ZAI_API_KEY", "")
    zai_endpoint = os.environ.get("ZAI_API_ENDPOINT", "https://api.z.ai/api/coding/paas/v4")
    glm_model = os.environ.get("GLM_MODEL", "glm-5-turbo")
    if zai_key:
        return zai_key, zai_endpoint.rstrip("/"), model or glm_model

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The pipeline can persist checkpoint data containing the research question, fetched source content, intermediate findings, and metadata to an arbitrary file path without any explicit user-facing warning about sensitive data retention. In a deep-research skill, those artifacts may include confidential prompts, proprietary source material, or personal data, so silent persistence increases the risk of unintended disclosure through local storage, backups, or later reuse.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.