Back to skill

Security audit

SherpaMind

Security checks for vulnerabilities and agentic risk

Overview

SherpaMind matches its SherpaDesk purpose, but it needs review because it can send API credentials to a configurable endpoint and writes sensitive support data to local artifacts without strong permission controls.

Install only if you intend to run a local SherpaDesk data backend and trust this publisher with SherpaDesk support data. Keep the API endpoint at the official SherpaDesk host unless you deliberately trust a custom endpoint, check that .SherpaMind directories and exports are private to your user, and enable the background service only when you want ongoing sync on that machine.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
src/sherpamind/client.py:40
Finding

Configurable API Endpoint Can Exfiltrate SherpaDesk Credentials

Content
View full analysis
dict[str, str]: credentials = f"{self._auth_identity()}:{self.api_key}".encode("utf-8") encoded = base64.b64encode(credentials).decode("ascii") headers = { "Accept": "application/json", "Authorization": f"Basic {encoded}", } if self.api_user: headers["X-API-User"] = self.api_user return headers def _build_url(self, path: str) -> str: return f"{self.api_base_url.rstrip('/')}/{path.lstrip('/')}" @retry( stop=stop_after_attempt(4), wait=wait_exponential(multiplier=1, min=1, max=16), retry=retry_if_exception_type(httpx.HTTPError), reraise=True, ) def get(self, path: str, params: dict[str, Any] | None = None) -> Any: self.pacer.wait() try: with httpx.Client(timeout=self.timeout_seconds, headers=self._build_headers()) as client: response = client.get(self._build_url(path), params=params) ``` The destination is loaded without validation: ```python api_base_url=_env_or_file( "SHERPADESK_API_BASE_URL", file_values, "https://api.sherpadesk.com", ) or "https://api.sherpadesk.com", api_key=os.getenv("SHERPADESK_API_KEY") or _read_secret_file(paths.api_key_file), api_user=os.getenv("SHERPADESK_API_USER") or _read_secret_file(paths.api_user_file), ``` It can also be persisted through the CLI: ```python settings_file = stage_connection_settings( api_base_url=api_base_url, org_key=org_key, instance_key=instance_key, notify_channel=notify_channel, ) ``` ### Technical Analysis The client constructs an HTTP Basic Authorization header containing the API identity and API key, then sends it to the configurable `api_base_ ...[truncated 1791 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
src/sherpamind/documents.py:1449
Finding

Sensitive Ticket Content Is Exported Without Restrictive Filesystem Permissions

Content
View full analysis
dict: docs = build_ticket_documents(db_path, limit=limit) output_path.parent.m ...[truncated 3259 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/bootstrap.py:116
Finding

Bootstrap Executes Third-Party Packages Without Integrity Verification

Content
View full analysis
None: if venv_python(venv_root).exists(): return venv_root.parent.mkdir(parents=True, exist_ok=True) builder = venv.EnvBuilder(with_pip=True) builder.create(venv_root) def pip_install(venv_root: Path) -> None: python = venv_python(venv_root) requirements = repo_root() / "requirements.txt" subprocess.run([str(python), "-m", "pip", "install", "--upgrade", "pip"], check=True) subprocess.run([str(python), "-m", "pip", "install", "-r", str(requirements)], check=True) subprocess.run([str(python), "-m", "pip", "install", "-e", str(repo_root())], check=True) ``` The dependency file pins direct versions but does not provide hashes: ```text httpx==0.28.1 pydantic==2.11.9 python-dateutil==2.9.0.post0 tenacity==9.1.2 typer==0.15.4 rich==14.1.0 ``` ### Technical Analysis The bootstrap process downloads and executes Python packages from the pip index configured on the host. Direct versions are pinned, which reduces accidental upgrades, but package hashes and a reviewed transitive dependency lock are absent. The unconditional pip upgrade also retrieves and executes a remotely supplied package before application dependencies are installed. Pip configuration and environment variables can redirect installation to another index. This is necessary only to the extent that dependencies must be installed. Executing unverified packages from a mutable remote source is broader than the minimum trust required for a reproducible installation. This finding does not establish that any listed dependency is malicious. It identifies a supply-chain integrity weakness that becomes exploitable if the package source, package release, DNS/TLS trust path, or local pip ...[truncated 1199 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (55)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This code chunk does not substantiate the declared functionality. It is only a minimal module initializer that exports settings. While a single __init__.py file may be only part of a larger package, based strictly on the supplied chunk, the actual behavior is limited to package metadata/export behavior and does not match the detailed SherpaDesk capabilities claimed in the description. Therefore this should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a full SherpaDesk-focused backend/query skill with support-operations capabilities and possible local setup behavior. The supplied code chunk does none of that: it is only a small test for a RequestPacer rate-limiting utility. There is no evidence of SherpaDesk-specific logic, API integration, data querying, reporting, state management, or service installation. This is a materially different primary purpose, so it is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Yes, this is a mismatch. The description presents a full SherpaDesk data-access and analysis skill with operational reporting and possible local setup behavior. The actual code shown does not implement any of those capabilities; it only tests a helper function for parsing timestamps. While timestamp parsing could be a supporting detail within a SherpaDesk-related project, this chunk’s behavior is materially narrower and does not substantiate the declared primary purpose. Therefore the declared description does not accurately represent what this supplied code chunk actually does.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/run.py (reported line 39)May include surrounding context.

python
def main() -> int:
    python = ensure_bootstrap()
    env = os.environ.copy()
    env.setdefault("SHERPAMIND_WORKSPACE_ROOT", str(workspace_root()))
    env["PYTHONPATH"] = str(repo_root() / "src") + (os.pathsep + env["PYTHONPATH"] if env.get("PYTHONPATH") else "")
    cmd = [str(python), "-m", "sherpamind.cli", *sys.argv[1:]]

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

Treat user-level systemd installation as a later, explicit operator decision after bootstrap, credential staging, discovery, and seed validation are complete.

If the target host does not support usable systemctl --user, the install is still valid in fallback mode, but the operator/agent should say so plainly and use:

bash
python3 scripts/run.py service-run-once

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill explicitly instructs use of shell commands, file reads/writes, network access, environment-based credentials, package installation, and optional service installation, yet it declares no tool-scope restrictions. That leaves an execution environment free to grant broader capabilities than necessary, increasing the blast radius if the skill is misused, compromised, or triggered unexpectedly.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger language is broad enough to activate on many generic support-related requests, potentially invoking a skill that can access local data, credentials, shell commands, and optional service-management flows when the user did not specifically intend that tool. In context, this is more dangerous because the skill handles sensitive support data and operational setup tasks, so accidental invocation could expose data or initiate high-risk actions.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The skill documents installation of a user-level background service and fallback long-running service modes, creating persistence on the host outside the immediate interactive session. Persistence is security-sensitive because it extends code execution duration, can continue handling privileged data or credentials after the original task ends, and may be unexpected if not tightly consented and scoped.

Content

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

md
Default expectation on Linux is that `setup` initializes the DB, cleans up any old SherpaMind cron jobs, and can generate an initial public snapshot. Treat user-level `systemd` installation as a later, explicit operator choice rather than part of the earliest bootstrap steps.

If service installation fails because the target host lacks usable `systemctl --user`, continue the bootstrap/config/seed flow anyway, report the service limitation clearly, and use `python3 scripts/run.py service-run-once` or `python3 scripts/run.py service-run` as the fallback operational mode instead of pretending the service installed.

If install/runtime/use issues or meaningful feature gaps are discovered while operating SherpaMind, check <https://github.com/kklouzal/SherpaMind/issues>. If a matching issue exists, add supporting detail; otherwise open a new issue with clear reproduction/context. Keep issue content anonymized and public-safe.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The bootstrap path performs package installation and likely network access automatically, but provides no user-facing notice, consent prompt, or dry-run mode. This is risky because setup can modify the local environment and pull code from external sources, increasing exposure to supply-chain compromise or unexpected system changes.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/bootstrap.py (reported line 123)May include surrounding context.

python
def pip_install(venv_root: Path) -> None:
    python = venv_python(venv_root)
    requirements = repo_root() / "requirements.txt"
    subprocess.run([str(python), "-m", "pip", "install", "--upgrade", "pip"], check=True)
    subprocess.run([str(python), "-m", "pip", "install", "-r", str(requirements)], check=True)
    subprocess.run([str(python), "-m", "pip", "install", "-e", str(repo_root())], check=True)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/bootstrap.py (reported line 124)May include surrounding context.

python
python = venv_python(venv_root)
    requirements = repo_root() / "requirements.txt"
    subprocess.run([str(python), "-m", "pip", "install", "--upgrade", "pip"], check=True)
    subprocess.run([str(python), "-m", "pip", "install", "-r", str(requirements)], check=True)
    subprocess.run([str(python), "-m", "pip", "install", "-e", str(repo_root())], check=True)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
89% confidence
Finding

Installing the local repository in editable mode executes packaging/build hooks from the repo during bootstrap, which can run arbitrary code if the skill contents are malicious or tampered with. In the context of an agent skill, this is more dangerous because users may treat setup as routine and unknowingly execute untrusted repository code on their machine.

Content

Scanner excerpt · scripts/bootstrap.py (reported line 125)May include surrounding context.

python
requirements = repo_root() / "requirements.txt"
    subprocess.run([str(python), "-m", "pip", "install", "--upgrade", "pip"], check=True)
    subprocess.run([str(python), "-m", "pip", "install", "-r", str(requirements)], check=True)
    subprocess.run([str(python), "-m", "pip", "install", "-e", str(repo_root())], check=True)


def main() -> int:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/run.py (reported line 33)May include surrounding context.

python
if python.exists():
        return python
    bootstrap = repo_root() / "scripts" / "bootstrap.py"
    subprocess.run([sys.executable, str(bootstrap)], check=True)
    return python

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The script invokes another Python program via subprocess.run to bootstrap the environment, which is a safety-relevant operation for code files under this rule. There is no confirmation prompt, print/log statement, or explanatory comment/docstring in this file disclosing that it will execute another script automatically.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script assembles and executes a child process for sherpamind.cli using subprocess.call, which is explicitly in scope for missing-warning checks on code files. This file does not include any confirmation prompt, visible log/print, or explanatory comment/docstring informing the user that it will spawn another process.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/run.py (reported line 43)May include surrounding context.

python
env.setdefault("SHERPAMIND_WORKSPACE_ROOT", str(workspace_root()))
    env["PYTHONPATH"] = str(repo_root() / "src") + (os.pathsep + env["PYTHONPATH"] if env.get("PYTHONPATH") else "")
    cmd = [str(python), "-m", "sherpamind.cli", *sys.argv[1:]]
    return subprocess.call(cmd, env=env, cwd=str(repo_root()))


if __name__ == "__main__":

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The skill metadata frames the tool as SherpaDesk data lookup and analysis, but this code introduces local cron-management capabilities through subprocess calls to an external CLI. That mismatch expands the skill's authority into host automation control, increasing the chance of unintended system modification or abuse if the capability is exposed through the agent.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · src/sherpamind/automation.py (reported line 26)May include surrounding context.

python
def _run(args: list[str]) -> subprocess.CompletedProcess[str]:
    return subprocess.run(args, text=True, capture_output=True, check=True)


def list_cron_jobs() -> dict[str, Any]:

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This function actively removes OpenClaw cron jobs, which is a destructive host-side action unrelated to normal SherpaDesk querying. In an agent setting, hidden cleanup behavior can disable scheduled tasks or interfere with other tooling, especially because the managed names are hardcoded and deletion occurs automatically for every matching job.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The cron removal loop executes destructive subprocess actions without any in-code confirmation, warning, or safety gate. In a conversational or automated environment, this creates a realistic risk of accidental or indirect invocation leading to unauthorized deletion of scheduled jobs and disruption of background processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The export commands write ticket documents, chunks, and embedding-ready data to disk, which can affect user data handling and create privacy exposure, but these commands provide no confirmation prompt or explicit user-facing warning in this file. The functions simply resolve an output path and perform the export, so a user invoking them from the CLI is not warned that potentially sensitive support data will be materialized into local files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This module creates directories and writes extensively to a local SQLite database, including destructive replacement behavior later in the file, but there are no comments, docstrings, prompts, or user-facing logs warning that local ticket/account/user data will be persisted. For a code file handling file writes affecting user and system data, some visible disclosure is expected unless clearly documented elsewhere in the skill description, which is not present in this file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code unconditionally deletes all attachment rows for a ticket before reinserting the current set, which is a destructive operation that can remove previously stored local data. There is no confirmation, warning comment, or user-visible logging around this behavior in the file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This function deletes all stored ticket_documents rows for the affected ticket IDs before inserting replacements, making the operation destructive for local cached data. The file does not provide any prompt, explanatory docstring, or user-visible logging to disclose that prior document records will be removed and rewritten.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The function removes all chunk rows for the specified ticket IDs before inserting new chunk data, which is an irreversible local cache replacement step. No confirmation, warning text, or user-facing log in this file informs the user that previously stored chunk data will be deleted.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.