Back to skill

Security audit

Multi Engine Search for Agent

Security checks for vulnerabilities and agentic risk

Overview

This is a real Novada search/extraction skill, but it needs user review because it sends queries and URLs to Novada and can generate unsafe shell commands from search results.

Install only if you are comfortable sending search terms, target URLs, and a Novada API key to Novada. Avoid using it with private documents, intranet URLs, regulated data, or secrets in URLs. Do not auto-run or paste action-links output into a shell without reviewing and sanitizing every URL, and prefer agent-json or normal link output instead.

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

Warning
Location
novada_search.py:399
Finding

API Credential Exposed in URL Query Parameters

Content
View full analysis
dict: """Call Novada search endpoint. Supports all 9 engines + Google sub-types.""" key = load_key() if not key: raise NovadaConfigError( "Missing NOVADA_API_KEY. Set env var, pass --api-key, or add NOVADA_API_KEY to a local .env" ) query_param = ENGINE_QUERY_PARAM.get(engine, "q") params = { "engine": engine, query_param: query, "api_key": key, "fetch_mode": fetch_mode, "num": str(max_results), } # Yelp needs a location parameter if not embedded in query if engine == "yelp": params["find_loc"] = "" # let provider auto-detect / use query context # Add Google sub-type if applicable if engine == "google" and google_type and google_type != "search": params["google_type"] = google_type url = NOVADA_SEARCH_URL + "?" + urllib.parse.urlencode(params) ``` The extraction path repeats the same pattern at lines 441-454: ```python params = { "engine": "google", "q": "", "url": url_to_extract, "api_key": key, "fetch_mode": fetch_mode, "extract_mode": "content", } url = NOVADA_SEARCH_URL + "?" + urllib.parse.urlencode(params) ``` ### Technical Analysis The Novada API key is required for the Skill's declared search and extraction functionality, and transmitting it to the declared Novada endpoint is expected. However, placing the credential in the URL query string is not the minimum-risk authentication mechanism. URLs are frequently recorded in locations that HTTP headers and request bodies are not, including: - Reverse-proxy and API-gateway acc ...[truncated 1889 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
novada_search.py:1287
Finding

Shell Command Injection Through Unescaped Search-Result URLs

Content
View full analysis
str: """Shell commands to open results directly.""" all_local = [] all_organic = [] for er in all_engine_results: if not er.get("error"): all_local.extend(er.get("local_results", [])) all_organic.extend(er.get("organic_results", [])) analysis = analyze_businesses(all_local) lines = [f"# Action Commands for: '{query}'", "", "Copy and run any command:", ""] if analysis.get("top_recommendations"): lines.append("## Local Businesses") lines.append("") for biz in analysis["top_recommendations"][:5]: lines.append(f"# {biz['name']}") lines.append(f"open \"{biz.get('maps_url', '')}\"") lines.append("") if all_organic: lines.append("## Web Sources") lines.append("") for item in all_organic[:5]: lines.append(f"# {item['title'][:50]}") lines.append(f"open \"{item['url']}\"") lines.append("") return "\n".join(lines) ``` The corresponding documentation encourages execution of this output by describing `action-links` as shell commands for automation and by emitting the instruction “Copy and run any command.” ### Technical Analysis Organic-result URLs are supplied by an external search API and ultimately originate from untrusted web content. The formatter inserts each URL directly into a double-quoted shell command without shell-safe quoting, validation, or character restrictions: ```sh open "" ``` Double quotes do not suppress every form of shell evaluation. In common POSIX shells, command substitution using `$(...)` or backticks is still evaluated inside double quotes. A liter ...[truncated 2259 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (18)

Tainted flow: 'req' from os.environ.get (line 368, credential/environment) → urllib.request.urlopen (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 · novada_search.py (reported line 369)May include surrounding context.

python
for attempt in range(max_retries + 1):
        try:
            req = urllib.request.Request(url, headers=headers, method="GET")
            with urllib.request.urlopen(req, timeout=timeout) as resp:
                return resp.read().decode("utf-8", errors="replace")
        except urllib.error.HTTPError as e:
            body = e.read().decode("utf-8", errors="replace") if hasattr(e, "read") else ""

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- "./SKILL.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 · novada_search.py (reported line 301)May include surrounding context.

python
# ============================================================================

def load_key() -> Optional[str]:
    """Resolve NOVADA_API_KEY from CLI override, environment, or local .env"""
    global CLI_API_KEY
    if CLI_API_KEY:
        debug_log("Using NOVADA_API_KEY from --api-key flag")

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 · novada_search.py (reported line 312)May include surrounding context.

python
# ============================================================================

def load_key() -> Optional[str]:
    """Resolve NOVADA_API_KEY from CLI override, environment, or local .env"""
    global CLI_API_KEY
    if CLI_API_KEY:
        debug_log("Using NOVADA_API_KEY from --api-key flag")

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 · novada_search.py (reported line 321)May include surrounding context.

python
# ============================================================================

def load_key() -> Optional[str]:
    """Resolve NOVADA_API_KEY from CLI override, environment, or local .env"""
    global CLI_API_KEY
    if CLI_API_KEY:
        debug_log("Using NOVADA_API_KEY from --api-key flag")

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 · novada_search.py (reported line 399)May include surrounding context.

python
# ============================================================================

def load_key() -> Optional[str]:
    """Resolve NOVADA_API_KEY from CLI override, environment, or local .env"""
    global CLI_API_KEY
    if CLI_API_KEY:
        debug_log("Using NOVADA_API_KEY from --api-key flag")

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill promotes extracting content from arbitrary URLs but does not clearly warn that the supplied URL and fetched page content are sent to the external Novada API service. In an agent setting, this can lead to unintentional transmission of sensitive internal links, private documents, or intranet resources to a third party, especially when users assume extraction is local.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation states the tool is effectively read-only, but also advertises an action-links format that emits shell open commands for automation. Even if those commands are not executed by the skill itself, agent ecosystems may automatically consume or run generated commands, creating a gap between the stated safety model and actual behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This server forwards user-supplied search queries and arbitrary URLs to an external HTTP-backed service via client.search, client.extract, and client.research without any in-file disclosure, consent, or policy gating. In an agent context, this can cause sensitive prompts, internal URLs, tokens embedded in URLs, or proprietary research targets to be transmitted to a third party, creating a real privacy and data-handling risk even if the behavior is the intended feature.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The search and extract functions send user queries, URLs, and the API key to a remote third-party service without any explicit disclosure or consent mechanism. In agent contexts, users may not realize their input and referenced URLs are being transmitted externally, which creates data leakage and compliance risk if sensitive prompts, internal URLs, or secrets are included.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The action-links mode generates shell commands such as open "" from remote search results. In an agent setting, this crosses from passive search into action execution and can enable unsafe follow-on behavior, especially if downstream components automatically execute or present these commands without validation. The risk is heightened because the URLs originate from external search results and may direct users or agents to malicious sites.

Content

No source excerpt is available for this finding.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Confidence
91% confidence
Finding

The code explicitly encourages users to 'Copy and run any command' and emits shell commands derived from remote result data. In an agent ecosystem, presenting executable commands materially increases the chance of unsafe tool use or command execution, even if the current command is limited to opening URLs. This is more dangerous in a search skill because command generation is outside its core read-only role.

Content

Scanner excerpt · novada_search.py (reported line 1297)May include surrounding context.

python
all_organic.extend(er.get("organic_results", []))
    analysis = analyze_businesses(all_local)

    lines = [f"# Action Commands for: '{query}'", "", "Copy and run any command:", ""]
    if analysis.get("top_recommendations"):
        lines.append("## Local Businesses")
        lines.append("")

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The module-level description presents the skill as a search platform/API, but research() performs a second-stage content extraction workflow over top search hits. Full-page retrieval/extraction is a materially broader capability than returning search results, especially when applied automatically across multiple discovered URLs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

Research mode performs follow-on extraction of top result URLs by sending them to the remote API, which can disclose browsing targets or sensitive user intent beyond the initial search. In an agent workflow this hidden second-stage network action is riskier because it increases external data sharing and could process internal or confidential URLs if such results are ever included.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This code creates a results directory and writes benchmark output to results/latest.json, but there is no warning before the file write occurs and no inline comment or docstring describing that local data will be persisted. The final print happens only after the write, so users are not informed in advance of the filesystem side effect.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The skill hardcodes language-specific trigger keywords across multiple locales, which creates implicit language behavior without explaining to users how language detection or multilingual matching is applied. This may violate a language/locale policy where locale-specific behavior should be explicit or user-selectable.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: setuptools has 10 known advisory(ies) (CVE-2013-1633 (Setuptools vulnerable to Man-in-the-middle attacks); CVE-2025-47273 (setuptools has a path traversal vulnerability in PackageIndex.download that lead); CVE-2024-6345 (setuptools vulnerable to Command Injection via package URL) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The build dependency is specified as setuptools>=68.0 without an upper bound or exact pin, so the actual installed version is environment-dependent and cannot be verified against known advisories. While this does not guarantee exploitation in this file by itself, it creates supply-chain uncertainty during builds and may allow vulnerable setuptools releases to be selected in some environments.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

The test data includes German and Chinese queries as fixed natural-language inputs, which suggests the skill is expected to handle multiple locales, but there is no accompanying natural-language indication of user language choice or documented locale policy. Because SQP-3 covers language or locale policy violations in natural-language content across all file types, these embedded strings may reflect an implicit locale policy without opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.