Back to skill

Security audit

TBOT Controller

Security checks for vulnerabilities and agentic risk

Overview

This trading-control skill has useful TBOT functions, but its webhook mode can send authenticated trade signals without the documented confirmation guard and can expose webhook secrets.

Review before installing. Use this only with a clearly identified paper/live TBOT runtime, do not let agents invoke JSON mode for previews, avoid TBOT_WEBHOOK_URL values outside trusted local endpoints, and assume JSON mode may send real trade instructions and reveal the webhook key unless the skill is fixed.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/tbotjson.py:319
Finding
Webhook secret is printed and transmitted to a caller-controlled destination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tbotjson.py:99-164, 188-203, 319-341` **Vulnerability Type**: Sensitive credential exposure and unrestricted outbound transmission **Risk Level**: High ### Complete Code Snippet ```python def _discover_runtime_env() -> Dict[str, str]: """Load the first .env we can find from candidate runtime dirs.""" for d in _candidate_runtime_dirs(): env_path = d / ".env" if env_path.exists() and env_path.is_file(): return _parse_dotenv(env_path) return {} def _resolve_webhook_key(cli_key: str) -> str: if cli_key: return cli_key env_key = os.getenv("WEBHOOK_KEY", "").strip() if env_key: return env_key dotenv = _discover_runtime_env() for k in ("WEBHOOK_KEY", "TBOT_WEBHOOK_KEY", "TVWB_KEY", "TV_WEBHOOK_KEY"): v = (dotenv.get(k) or "").strip() if v: return v unique_key = _resolve_unique_key(dotenv) if unique_key: return _generate_webhook_key(unique_key) for k, v in dotenv.items(): if re.search(r"webhook", k, re.I) and re.search(r"key", k, re.I) and v.strip(): return v.strip() return "" def _resolve_unique_key(dotenv: Dict[str, str]) -> str: unique_key = os.getenv("TVWB_UNIQUE_KEY", "").strip() if unique_key: return unique_key unique_key = (dotenv.get("TVWB_UNIQUE_KEY") or "").strip() if unique_key: return unique_key for d in _candidate_runtime_dirs(): key_path = d / ".keyfile" if key_path.exists() and key_path.is_file(): try: return key_path.read_text().strip() except Exception: continue return "" def post_json(url: str, payload: Dict[str, Any]) -> Tuple[int, str]: data = json.dumps(payload).encode("utf-8") req = request.Request( url, data=data, headers={"Content-Type": "application/json"}, method="POST", ...[truncated 2965 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never print or persist the unredacted webhook key: - Replace `payload["key"]` with a fixed redaction marker before logging. - Do not write the key to `--out` unless the user explicitly requests an unsafe raw export. - Ensure exception messages and response logging cannot echo credentials. 2. Restrict outbound destinations: - Permit loopback destinations by default. - Require an explicit security override for remote hosts. - Maintain an allowlist of trusted schemes, hosts, and ports. - Reject user-information URL components and non-HTTP(S) schemes. - Require HTTPS for all non-loopback destinations. 3. Handle redirects securely: - Disable redirects for authenticated POST requests, or only follow redirects that preserve the exact approved origin. - Never forward a secret-bearing request across origins. 4. Reduce secret-file discovery: - Prefer an explicitly configured credential source. - Do not scan generic current and parent directories for `.env` or `.keyfile`. - Verify ownership and restrictive permissions before reading credential files. 5. Separate diagnostic output from payload output: - Print only a redacted summary containing the destination, ticker, direction, and quantity. - Keep the secret solely in memory for the minimum time necessary. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/tbotjson.py:303
Finding
Trade-capable webhook transmission bypasses the documented confirmation requirement<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tbotjson.py:303-341` **Vulnerability Type**: Missing authorization and confirmation control for state-changing trading actions **Risk Level**: Critical ### Complete Code Snippet ```python def main() -> int: p = argparse.ArgumentParser( description="Generate schema-valid TBOT webhook JSON and send to TBOT webhook" ) p.add_argument("--ticker", required=True) p.add_argument("--direction", default="") p.add_argument("--orderRef", default="") p.add_argument("--contract", default="") p.add_argument( "--close", type=int, default=None, help="Close position qty (sets strategy.close, contract stock, qty metric)", ) p.add_argument("--currency", default=os.getenv("DEFAULT_CURRENCY", "USD")) p.add_argument("--timeframe", default=os.getenv("DEFAULT_TIMEFRAME", "1D")) p.add_argument("--clientId", type=int, default=int(os.getenv("DEFAULT_CLIENT_ID", "1"))) p.add_argument("--metric", action="append", default=[]) p.add_argument("--key", default=os.getenv("WEBHOOK_KEY", "")) p.add_argument("-o", "--out", default="") p.add_argument("--url", default=os.getenv("TBOT_WEBHOOK_URL", ""), help="TBOT webhook URL (or set TBOT_WEBHOOK_URL)") args = p.parse_args() args.key = _resolve_webhook_key(args.key) if not args.key: raise SystemExit("Missing webhook key (set WEBHOOK_KEY or put it in the runtime .env)") schema = load_schema() payload = build_payload(args) # If user did not provide direction and did not use --close, assume close intent. if not args.direction: args.direction = "strategy.close" payload["direction"] = args.direction validate_schema(payload, schema) out = json.dumps(payload, indent=2) if args.out: Path(args.out).write_text(out + "\n") print(out) args.url = _resolve_webhook_url(args.url) if not args.url: raise Sy ...[truncated 2486 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add an explicit confirmation flag to JSON sending: - Define `--run-it`. - Require `--run-it` or `RUN_IT=1` before any network transmission. - Fail closed if confirmation is absent. 2. Separate generation from transmission: - Make JSON generation the default, offline behavior. - Introduce an explicit `send` subcommand or `--send --run-it` combination. - Ensure `-o` only writes a generated payload and does not implicitly send it. 3. Require explicit trading intent: - Remove the automatic `strategy.close` fallback. - Require the caller to specify direction and quantity. - Reject zero, negative, non-integral, or implausibly large quantities according to the selected contract type. 4. Verify execution environment: - Determine whether the runtime is paper or live. - Refuse to send when the mode is unknown. - For live mode, require stronger confirmation that displays destination, account mode, ticker, direction, and quantity. 5. Add policy-oriented validation beyond JSON Schema: - Allowlist supported directions, contracts, and metric names. - Enforce operation-specific required metrics. - Apply configurable order-size and notional-value limits. ]]>

T01 · Skill Instruction Hijacking

Error
Location
README.md:81
Finding
Documentation falsely describes an unconditional network sender as an offline JSON generator<![CDATA[ ## Vulnerability Details **File Location**: `README.md:81-92`, `SKILL.md:211-216`, `scripts/tbotjson.py:337-341` **Vulnerability Type**: Misleading safety instructions that conceal a state-changing network operation **Risk Level**: High ### Complete Code Snippet The README describes the operation as offline: ```markdown ## Webhook JSON Generator Builds a schema-valid TradingView-style payload (no network calls). ```bash bash scripts/tbot.sh json \ --ticker IBM \ --direction strategy.entrylong \ --orderRef r1 \ --contract stock \ --metric qty=500 \ --key "WebhookReceived:123456" \ -o payload.json ``` ``` The skill instructions similarly claim: ```markdown Guarantees: - Output is validated against `alert_webhook_schema.json` - Unsupported directions or metrics fail fast - No network calls or broker actions are performed - This generator is independent of the gateway container image (e.g., gnzsnz/ib-gateway). ``` The implementation performs an unconditional network transmission: ```python args.url = _resolve_webhook_url(args.url) if not args.url: raise SystemExit("Missing webhook URL (set TBOT_WEBHOOK_URL)") status_code, response_text = post_json(args.url, payload) print(f"SENT {status_code} {args.url}") if not (200 <= status_code <= 299): import sys print(f"ERROR response: {response_text}", file=sys.stderr) return 2 ``` ### Technical Analysis The user- and agent-facing documentation states that JSON mode makes no network calls and performs no broker actions. In reality, the implementation always sends the authenticated payload after validation. This discrepancy is security-relevant because an agent may load the skill instructions and treat JSON mode as a harmless formatting operation. The misleading guarantee can therefore alter the agent's risk assessment and cause it to invoke a state-changing operation without obtaining appropriate user authorization. The discrepancy is reinforced by the lack of a generate-o ...[truncated 1045 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Correct all documentation to match implementation behavior: - Explicitly state whether a command generates, writes, or sends a payload. - Remove all claims that current JSON mode makes no network calls. - Clearly warn that webhook delivery may trigger live broker activity. 2. Prefer changing the implementation to match the safer documentation: - Make JSON mode generate-only by default. - Require an explicit `send` operation and confirmation flag for transmission. 3. Document all sensitive data flows: - Identify credential sources, including environment variables, `.env`, and `.keyfile`. - Explain that the key is included in the transmitted payload. - State destination restrictions and transport-security requirements. 4. Add automated consistency tests: - Verify that generate-only examples do not make network calls. - Fail documentation tests if command behavior changes without corresponding documentation updates. 5. Require the agent to report the paper/live mode, destination, direction, and quantity before invoking any sending operation. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/requirements.txt:1
Finding
Automatically installed Python dependency is not reproducibly pinned<![CDATA[ ## Vulnerability Details **File Location**: `scripts/requirements.txt:1`, `scripts/tbot.sh:14-16` **Vulnerability Type**: Unpinned automatically resolved third-party dependency **Risk Level**: Medium ### Complete Code Snippet ```text jsonschema>=4.0.0 ``` ```bash REQ_FILE="$SCRIPT_DIR/requirements.txt" # Prefer uv (OpenClaw-native). It creates an isolated env and installs deps on demand. if command -v uv >/dev/null 2>&1; then PYTHON_EXEC=(uv run --no-project --with-requirements "$REQ_FILE" python3) ``` ### Technical Analysis The requirement specifies only a lower version bound. The entrypoint uses `uv` to resolve and install dependencies on demand, so different invocations may execute different future releases of `jsonschema` and its transitive dependencies. No lockfile, exact version constraint, or package hash is present. Consequently, reviewed source code does not fully determine the code that will execute at runtime. This does not prove that the current dependency is malicious. It is a supply-chain hardening weakness that increases exposure to compromised releases, incompatible updates, malicious package-index configuration, or future transitive dependency changes. ### Attack Path 1. The user invokes `scripts/tbot.sh`. 2. `uv` resolves `jsonschema>=4.0.0` and its transitive dependencies against the configured package index. 3. A compromised package release, compromised index, or unsafe alternate index supplies malicious dependency code. 4. The dependency is installed into the isolated environment. 5. Python imports the package during `tbotjson.py` execution. 6. Malicious package initialization code executes with the same local privileges as the skill. ### Impact Assessment A compromised dependency could access files, environment variables, runtime credentials, webhook keys, database paths, and network resources available to the invoking user. It could also modify payloads or execute arbitrary commands with that user's privileges. The ...[truncated 130 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin reviewed dependency versions exactly rather than using an open-ended lower bound. 2. Generate and commit a `uv` lockfile covering direct and transitive dependencies. 3. Enforce package hashes where supported. 4. Configure a trusted package index explicitly and avoid untrusted extra indexes. 5. Use automated dependency scanning and controlled update pull requests. 6. Re-review the lockfile whenever dependency versions change. 7. Consider removing the runtime dependency by using a narrowly scoped, locally reviewed validator if the schema requirements are simple enough. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill presents itself as a controlled automation interface with DB-first queries, yet it also documents direct webhook transmission, secret loading from runtime configuration, and immediate action dispatch. In a trading context, that mismatch is especially dangerous because it can convert a seemingly informational skill into one capable of initiating trade-related actions over the network.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill presents itself as a controlled automation interface with DB-first queries, yet it also documents direct webhook transmission, secret loading from runtime configuration, and immediate action dispatch. In a trading context, that mismatch is especially dangerous because it can convert a seemingly informational skill into one capable of initiating trade-related actions over the network.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The JSON mode section contains direct internal contradictions about whether network activity occurs. Security controls, reviewers, and users rely on this documentation to understand execution risk; contradictory guidance can lead to unsafe automation of trade-triggering requests under the false assumption that the mode is offline-only.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The documentation simultaneously claims JSON mode sends payloads to a TBOT webhook and that it performs no network calls or broker actions. This contradiction can cause an agent or user to treat a state-changing network action as harmless output generation, which is highly risky when the endpoint may trigger live or paper trades.

Credential Access

High
Category
Privilege Escalation
Content
"Set it to the folder that contains docker-compose.yml (e.g. .../openclaw-on-tradingboat)."
        )

    # UX guardrails: help first-time users when .env is missing.
    compose_yml = os.path.join(compose_dir, "docker-compose.yml")
    if not os.path.exists(compose_yml):
        raise SystemExit(
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"Set it to the folder that contains docker-compose.yml (e.g. .../openclaw-on-tradingboat)."
        )

    # UX guardrails: help first-time users when .env is missing.
    compose_yml = os.path.join(compose_dir, "docker-compose.yml")
    if not os.path.exists(compose_yml):
        raise SystemExit(
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"Set COMPOSE_DIR to the openclaw-on-tradingboat folder."
        )

    env_path = os.path.join(compose_dir, ".env")
    if not os.path.exists(env_path):
        sample = os.path.join(compose_dir, ".env.sample")
        stable_dotenv = os.path.join(compose_dir, "stable", "tbot", "dotenv")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
Behavior:
 - This command ALWAYS sends the generated, schema-validated JSON payload to TBOT.
 - Webhook endpoint is taken from (in order): --url, TBOT_WEBHOOK_URL, or defaults to http://127.0.0.1:5001/webhook.
 - Webhook key is taken from (in order): --key, WEBHOOK_KEY env var, or the runtime .env file (auto-discovered).
 - orderRef defaults to Close_<TICKER>_<QTY>_<epoch_ms> when omitted.
 - If --close <QTY> is provided, direction defaults to strategy.close and contract defaults to stock.
"""
Confidence
92% confidence
Finding
The documented behavior states that the webhook key will be pulled from environment variables or an auto-discovered runtime .env file. In an agent skill, automatic retrieval of secrets from local configuration increases the chance that sensitive credentials are used without explicit operator intent, enabling unauthorized authenticated requests to the TBOT webhook.

Credential Access

High
Category
Privilege Escalation
Content
def _parse_dotenv(path: Path) -> Dict[str, str]:
    """Minimal .env parser (KEY=VALUE, ignores comments/blank lines)."""
    out: Dict[str, str] = {}
    try:
        for raw in path.read_text().splitlines():
Confidence
90% confidence
Finding
The _parse_dotenv helper reads arbitrary KEY=VALUE entries from a local .env file, enabling the script to ingest secrets from files outside a narrowly defined trust boundary. In a multi-project workspace or agent environment, this broad file-based secret access can unintentionally harvest credentials from unrelated contexts.

Credential Access

High
Category
Privilege Escalation
Content
def _discover_runtime_env() -> Dict[str, str]:
    """Load the first .env we can find from candidate runtime dirs."""
    for d in _candidate_runtime_dirs():
        env_path = d / ".env"
        if env_path.exists() and env_path.is_file():
Confidence
95% confidence
Finding
The runtime environment discovery routine walks candidate directories and loads the first .env file it finds, creating a broad and implicit secret search capability. This can lead to credential misuse, confused-deputy behavior, or accidental use of secrets from an unintended runtime when the skill is executed from different working directories.

Credential Access

High
Category
Privilege Escalation
Content
def _discover_runtime_env() -> Dict[str, str]:
    """Load the first .env we can find from candidate runtime dirs."""
    for d in _candidate_runtime_dirs():
        env_path = d / ".env"
        if env_path.exists() and env_path.is_file():
            return _parse_dotenv(env_path)
    return {}
Confidence
95% confidence
Finding
The specific check for '.env' existence inside discovered candidate directories is part of an automated secret-hunting flow that operationalizes credential collection. Because those credentials are later used to authenticate outbound webhook requests, the behavior materially increases the danger of unauthorized command execution against TBOT.

Credential Access

High
Category
Privilege Escalation
Content
if unique_key:
        return unique_key

    # From runtime .env
    unique_key = (dotenv.get("TVWB_UNIQUE_KEY") or "").strip()
    if unique_key:
        return unique_key
Confidence
96% confidence
Finding
The code not only reads explicit webhook keys but also recovers a unique seed from .env or .keyfile and derives a valid webhook key from it. This effectively converts locally stored secret material into active authentication for control-plane requests, which is particularly risky in an agent skill that can be invoked indirectly.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
estamp": int(time.time() * 1000),
        "ticker": args.ticker,
        "timeframe": args.timeframe,
        "currency": args.currency,
        "clientId": args.clientId,
        "key": args.key,
        "orderRef": args.orderRef,
        "contract": args.contract,
        "direction": args.direction,
        "metrics": metrics,
    }


def main() -> int:
    p = argparse.ArgumentParser(
        description="Generate schema-valid TBOT webhook JSON and send to TBOT webhook"
    )

    # Required by schema
    p.add_argument("--ticker", required=True)
    p.add_argument("--direction", default="")
    p.add_argument("--orderRef", default="")
    p.add_argument("--contract", default="")
    p.add_argument(
        "--close",
        type=int,
        default=None,
        help="Close position qty (sets strategy.close, contract stock, qty metric)",
    )

    # Defaults allowed by policy
    p.add_argument("--currency", default=os.getenv("DEFAULT_CURRENCY", "USD"))
    p.add_argument("--ti
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Lp3

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding
The skill exposes powerful capabilities including shell execution, file access, environment access, and network behavior, but it declares no explicit tool scope or permission boundaries. In a trading-control skill, this omission increases the chance that an agent may invoke sensitive operations without clear sandboxing or policy enforcement, especially when the same skill can inspect runtime state, read config, and trigger webhook actions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The JSON mode documentation does not clearly warn that sending a webhook may trigger live trading actions. Given the domain is an automated trading stack, omission of a strong execution-risk warning materially increases the chance of accidental order placement or interference with a live environment.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
`json` mode generates a schema-valid TradingView-style payload and **sends it** to TBOT via webhook.

Defaults / inference rules (do not ask the user):
- **Webhook URL**: default `http://127.0.0.1:5001/webhook` (override with `TBOT_WEBHOOK_URL`).
- **Webhook key**: read from runtime `.env` (override with `WEBHOOK_KEY`).
- **orderRef**: if not provided, auto-generate `Close_<TICKER>_<QTY>_<epoch_ms>`.
Confidence
96% confidence
Finding
The instruction to avoid asking the user for details while generating and sending a webhook encourages autonomous execution of potentially trade-triggering actions. In this context, inferring webhook destination, authentication material, and order metadata without a confirmation step increases the risk of unintended or unauthorized trading operations.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- **Webhook URL**: default `http://127.0.0.1:5001/webhook` (override with `TBOT_WEBHOOK_URL`).
- **Webhook key**: read from runtime `.env` (override with `WEBHOOK_KEY`).
- **orderRef**: if not provided, auto-generate `Close_<TICKER>_<QTY>_<epoch_ms>`.
- **Close intent**: inferred automatically; do not prompt the user.

```bash
# Example (user: “close 50 NFLX now”)
Confidence
97% confidence
Finding
Automatically inferring close intent and instructing the agent not to prompt the user is unsafe in a trading skill because it collapses ambiguous natural language into an actionable trade signal. Combined with automatic webhook sending, this can produce irreversible actions against paper or live systems without sufficient human verification.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The manifest describes a controlled automation interface centered on DB-first queries and lifecycle control on explicit request. This router exposes a separate `json` mode and documents webhook-driven usage via `TBOT_WEBHOOK_URL`, which indicates event/HTTP-oriented automation not reflected in the manifest description.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run(cmd: List[str], *, cwd: str | None = None) -> int:
    p = subprocess.run(cmd, cwd=cwd)
    return p.returncode
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The script is explicitly designed to always transmit a generated payload to a webhook endpoint, which exceeds a narrowly described 'controlled automation interface' and removes any dry-run or approval boundary. In an agent skill context, automatic outbound actions against a trading control plane can trigger unintended or unauthorized lifecycle operations if the tool is invoked with attacker-influenced inputs.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The code searches multiple workspace directories for .env and .keyfile secrets, then derives usable webhook credentials from discovered material. That broad secret discovery behavior creates credential exposure and privilege expansion risk, especially for an agent-accessible tool that can operate across working directories without the user explicitly providing credentials.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
Purpose:
- Provide a *single* read-only probe endpoint that can infer where TBOT is running.
- Return structured JSON so OpenClaw can proceed without asking the user when possible.

This file MUST remain read-only:
- no start/stop/restart
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.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def _run_capture(cmd: List[str], cwd: str | None = None) -> Tuple[int, str, str]:
    p = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True)
    return p.returncode, p.stdout, p.stderr
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The DB commands expose potentially sensitive trading data including orders, positions, PnL, symbols, timestamps, and error details, and they do so without any access control, masking, confirmation prompt, or user-facing disclosure. In an agent-skill context, this increases the risk of unintended data exfiltration to the calling agent, logs, or downstream systems even though the database is opened read-only.

Missing User Warnings

Low
Confidence
77% confidence
Finding
The markdown documents an HTTP-based health check (`status health --base-url http://127.0.0.1:5001`) but does not explicitly warn that it performs network requests against a service endpoint. For markdown files, operations that affect privacy or system integrity should be disclosed so users understand external communication is occurring.

Static analysis

No suspicious patterns detected.