Back to skill

Security audit

Free Search Aggregator

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed web-search aggregator that writes search results locally and uses optional provider API keys, with some credential-handling and retention hygiene risks but no evidence of hidden or malicious behavior.

Install only if you are comfortable with searches and returned results being saved locally under memory. Use dedicated, restricted API keys for optional providers, avoid pasting secrets into search queries, clean stored reports/cache when needed, and pin or review the SearXNG Docker image before using that optional setup path.

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

T09 · Insecure Skill Coding Practices

Warning
Location
src/free_search/quota_real.py:103
Finding

Tavily API Key Exposure Through URL Query-String Fallback

Content
View full analysis

Vulnerability Details

File Location: src/free_search/quota_real.py:103-112
Vulnerability Type: API credential exposure in URL query parameters
Risk Level: Medium

Vulnerable Code

python
def _get_tavily_quota(api_key: str) -> RealQuotaResult:
    url = "https://api.tavily.com/usage"
    headers = {"Authorization": f"Bearer {api_key}"}
    params = {"api_key": api_key}

    # Try Authorization header first, then fallback to query param.
    try:
        resp = requests.get(url, headers=headers, timeout=10)
        if resp.status_code in (401, 403):
            resp = requests.get(url, params=params, timeout=10)

Technical Analysis

The quota-checking implementation initially sends the Tavily credential in an Authorization header, but after an HTTP 401 or 403 response it retries with the API key in the URL query string.

Although HTTPS encrypts the request in transit, query strings are commonly recorded in provider access logs, reverse-proxy logs, monitoring systems, exception telemetry, browser or HTTP debugging tools, and network observability products. Authorization headers are more commonly subject to explicit redaction than URL parameters.

The request is sent to Tavily's declared HTTPS endpoint, so this is not evidence of intentional credential exfiltration. Nevertheless, the fallback exceeds the safer authentication mechanism already implemented and unnecessarily increases credential exposure.

Attack Path

  1. An operator configures TAVILY_API_KEY.
  2. The operator invokes a real quota check using the --real CLI option or the Python API.
  3. Tavily returns HTTP 401 or 403 to the header-authenticated request.
  4. The Skill retries using ?api_key=<secret>.
  5. A provider, proxy, monitoring agent, or diagnostic system records the complete request URL.
  6. A party with access to those records extracts the key and reuses it against Tavily.

Impact Assessment

Successful exploitation does not grant local operating- ...[truncated 321 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove the query-string fallback and use only the documented authorization-header mechanism.
  • If Tavily requires a different fallback mechanism, prefer a request body over a URL parameter.
  • Treat HTTP 401 and 403 responses as authentication failures rather than automatically retransmitting the credential through a less secure channel.
  • Ensure HTTP clients, proxies, and telemetry systems redact sensitive query parameters.
  • Use narrowly scoped, revocable API keys and rotate any key suspected of appearing in logs.
  • Add a regression test that inspects prepared requests and verifies that the API key never appears in the URL.

T09 · Insecure Skill Coding Practices

Warning
Location
src/free_search/providers.py:694
Finding

Mojeek API Key Transmitted in a URL Query Parameter

Content
View full analysis

Vulnerability Details

File Location: src/free_search/providers.py:694-701
Vulnerability Type: API credential exposure in URL query parameters
Risk Level: Medium

Vulnerable Code

python
def _search_api(self, query: str, *, max_results: int, api_key: str) -> list[SearchItem]:
    """Use official Mojeek JSON API (requires MOJEEK_API_KEY)."""
    params = {"q": query, "api_key": api_key, "fmt": "json", "nb": max_results}
    try:
        logger.debug("Mojeek API request: query=%r max_results=%s", query, max_results)
        response = self.session.get(self.api_endpoint, params=params, timeout=self.timeout)

Technical Analysis

The Mojeek provider includes MOJEEK_API_KEY in the parameters of an HTTP GET request. The requests library serializes this value into the URL query string.

HTTPS protects the request against ordinary network interception, and the destination is the declared Mojeek API endpoint. However, credentials placed in URLs may be retained by the provider, gateways, reverse proxies, observability infrastructure, or debugging tools. This gives the credential a larger exposure surface than header-based authentication.

If the provider contract strictly requires query-string authentication, this behavior may be functionally necessary. It should still be treated as a credential-handling risk and accompanied by redaction, key scoping, and explicit documentation.

Attack Path

  1. An operator configures MOJEEK_API_KEY.
  2. A search reaches the Mojeek provider.
  3. The Skill issues a URL containing api_key=<secret>.
  4. An intermediary or provider-side component records the complete URL.
  5. A person or process with access to the retained logs obtains the API key.
  6. The key is reused to issue API requests or exhaust the victim's quota.

Impact Assessment

The issue does not provide local code execution or elevated system access. Its scope is the exposed Mojeek credential and the permissions assigned to it. An ...[truncated 176 chars]

Remediation
View remediation

Remediation Suggestions

  • Use an authorization header if the Mojeek API supports one.
  • If query-string authentication is mandatory, document that limitation clearly and use a dedicated, minimally privileged key.
  • Configure application, proxy, provider, and telemetry logging to redact the api_key parameter.
  • Avoid logging prepared request URLs or exception objects that could include the complete URL.
  • Rotate exposed keys and monitor their usage for unexpected requests.
  • Add tests that verify credentials are absent from URLs whenever a header-based authentication option is available.

T09 · Insecure Skill Coding Practices

Warning
Location
src/free_search/providers.py:930
Finding

Google Custom Search API Key Transmitted in a URL Query Parameter

Content
View full analysis

Vulnerability Details

File Location: src/free_search/providers.py:930-941
Vulnerability Type: API credential exposure in URL query parameters
Risk Level: Medium

Vulnerable Code

python
api_key = (self.config.get("api_key") or "").strip()
cx = (self.config.get("cx") or "").strip()
if not api_key:
    raise AuthError("Google CSE API key (GOOGLE_API_KEY) missing")
if not cx:
    raise AuthError("Google CSE search engine ID (GOOGLE_CX) missing")

# Google CSE returns at most 10 results per request
num = min(max_results, 10)

self.maybe_sleep_for_rate_limit()
params = {"key": api_key, "cx": cx, "q": query, "num": num}

try:
    logger.debug("Google CSE request: query=%r num=%s", query, num)
    response = self.session.get(self.endpoint, params=params, timeout=self.timeout)

Technical Analysis

The Google Custom Search implementation serializes GOOGLE_API_KEY into the request URL as the key parameter. This follows a commonly supported Google API invocation style, and the request is sent to Google's declared HTTPS endpoint. It is therefore within the Skill's search functionality and is not evidence of unrelated exfiltration.

Nevertheless, URL-based credentials can be retained in access logs, proxies, monitoring systems, and diagnostic captures. If the API key lacks appropriate API and application restrictions, disclosure may permit third parties to consume quota or invoke other Google APIs enabled for the same project.

Attack Path

  1. An operator configures GOOGLE_API_KEY and GOOGLE_CX.
  2. The Google CSE provider handles a search.
  3. The API key is serialized as ?key=<secret> in the HTTPS URL.
  4. The complete URL is retained by a provider, proxy, monitoring system, or debugging tool.
  5. An attacker with access to those records recovers the key.
  6. If key restrictions are absent or insufficient, the attacker reuses it to consume Custom Search quota or invoke other permitted Google APIs.

Impact Assessment

No lo ...[truncated 341 chars]

Remediation
View remediation

Remediation Suggestions

  • Use a non-URL authentication mechanism if Google Custom Search supports one for this integration.
  • Restrict the key to the Custom Search API and to the narrowest applicable client, network, or application context.
  • Use a separate key for this Skill rather than sharing a general-purpose project credential.
  • Redact the key query parameter from proxy, gateway, telemetry, and diagnostic logs.
  • Avoid emitting complete prepared request URLs in errors or debug output.
  • Set quota alerts, monitor anomalous use, and rotate credentials after suspected disclosure.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (47)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This finding highlights an important security-relevant mismatch: the skill claims no declared permissions while also implying config reads and persistent quota-state writes. Undeclared stateful disk access can surprise operators, affect privacy, and broaden the effective trust boundary beyond a simple search utility.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README explicitly states that search activity and artifacts are stored under memory/, but it does not clearly warn users that their queries and retrieved results persist on disk. In a search skill, queries may contain sensitive prompts, investigation topics, credentials pasted by mistake, or regulated data, so silent persistence increases privacy and data-handling risk.

Content

No source excerpt is available for this finding.

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · README.md (reported line 126)May include surrounding context.

md
scripts/search "openclaw" --max-results 3 --compact

# 3) Verify storage paths
ls -la /home/openclaw/.openclaw/workspace/memory/search-cache/ | tail -n 5
ls -la /home/openclaw/.openclaw/workspace/memory/search-index/
ls -la /home/openclaw/.openclaw/workspace/memory/search-reports/ | tail -n 5

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · README.md (reported line 127)May include surrounding context.

md
scripts/search "openclaw" --max-results 3 --compact

# 3) Verify storage paths
ls -la /home/openclaw/.openclaw/workspace/memory/search-cache/ | tail -n 5
ls -la /home/openclaw/.openclaw/workspace/memory/search-index/
ls -la /home/openclaw/.openclaw/workspace/memory/search-reports/ | tail -n 5

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · README.md (reported line 128)May include surrounding context.

md
scripts/search "openclaw" --max-results 3 --compact

# 3) Verify storage paths
ls -la /home/openclaw/.openclaw/workspace/memory/search-cache/ | tail -n 5
ls -la /home/openclaw/.openclaw/workspace/memory/search-index/
ls -la /home/openclaw/.openclaw/workspace/memory/search-reports/ | tail -n 5

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

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

md
scripts/search "openclaw" --max-results 3 --compact

# 3) Verify storage paths
ls -la /home/openclaw/.openclaw/workspace/memory/search-cache/ | tail -n 5
ls -la /home/openclaw/.openclaw/workspace/memory/search-index/
ls -la /home/openclaw/.openclaw/workspace/memory/search-reports/ | tail -n 5

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README prominently advertises that search results are automatically written to memory/, but it does not clearly warn users that potentially sensitive queries, URLs, and derived reports will be stored locally and retained over time. In an agent environment, search tasks may include confidential prompts or research topics, so silent persistence increases the risk of unintended data exposure to other tools, users, backups, or later processes.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises and documents capabilities that require network, shell, environment-variable access, and filesystem read/write, but it declares no explicit tool scope or permissions. In an agent ecosystem, this increases the chance the skill is granted broader access than users expect, making potentially sensitive operations like credential use, network probing, and disk writes insufficiently transparent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill documents that it writes search caches, indexes, reports, health data, and discovery telemetry under memory/ by default, but it does not prominently warn users about this persistence. Search queries and related metadata can contain sensitive research topics, internal URLs, or operator behavior, so silent default retention creates privacy and data-handling risk.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
88% confidence
Finding

The documentation instructs users to run a Docker image without a pinned tag or digest, which can pull an unexpected or maliciously changed image in the future. This creates supply-chain risk because the exact container contents are not reproducible or reviewable over time.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

The manifest frames this as a 'free-search-aggregator' for quota-aware multi-provider web search, but this wrapper explicitly pulls paid-provider credentials from environment variables and forwards them into execution. Accessing credential-bearing environment variables is a broader capability than a simple search entrypoint and is not clearly justified by the 'free-search' framing alone.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The task command persists the full task/query and returned search payload to storage automatically, with no explicit user notice, consent, or opt-out visible in this CLI path. Search queries often contain sensitive internal goals, investigation topics, or user data, so silently writing them under memory/ increases privacy and data-retention risk if local storage is later accessed by another user, process, or downstream tool.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The default search flow also automatically persists the raw query and results payload without warning the user at execution time. In the context of a multi-provider search aggregator that may be used by agents for research tasks, saved queries can reveal confidential prompts, targets, credentials accidentally pasted into searches, or sensitive investigative context.

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

python
CANDIDATE_SOURCES: list[dict[str, Any]] = [
    {
        "name": "marginalia",
        "probe_url": "https://api.marginalia.nu/{subpath}",
        "search_url": "https://search.marginalia.nu/search?query={query}&count={count}&format=json",
        "type": "json_api",
        "description": "Independent index focused on non-commercial/small websites",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code constructs outbound search requests and transmits the probe query to multiple third-party services, which is a network operation covered by the missing-warning rule for code files. While the module docstring describes discovery behavior, there is no user-facing confirmation, warning, or explicit disclosure near the HTTP request about contacting external public instances.

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 · src/free_search/providers.py (reported line 141)May include surrounding context.

python
class BraveProvider(BaseProvider):
    name = "brave"
    endpoint = "https://api.search.brave.com/res/v1/web/search"

    @staticmethod
    def _api_key_candidates(api_key: str) -> list[str]:

Static analysis

No suspicious patterns detected.