Back to skill

Security audit

Sentinel Modality-Router Redaction Check

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed local Sentinel gateway health check that can restart the gateway and optionally send results to Telegram, so it should be installed only where that behavior is expected.

Install this only in an environment where the operator is allowed to restart and reconfigure the local Sentinel gateway. Leave Telegram variables blank for local-only output, or assume diagnostic pass/fail data, trace links, and failure snippets may leave the machine. Do not adapt it to real user prompts or untrusted webhook arguments without adding validation, redaction, and confirmation controls.

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

T09 · Insecure Skill Coding Practices

Warning
Location
skill.py:281
Finding

Telegram Bot Token May Be Exposed in Error Logs

Content
View full analysis
bool: token = os.getenv("TELEGRAM_BOT_TOKEN") chat_id = os.getenv("TELEGRAM_CHAT_ID") if not token or not chat_id: print("[skill] TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID not set -- skipping alert.") return False try: resp = requests.post( f"https://api.telegram.org/bot{token}/sendMessage", json={"chat_id": chat_id, "text": message, "parse_mode": "HTML"}, timeout=10, ) resp.raise_for_status() return True except requests.RequestException as exc: print(f"[skill] Telegram send failed: {exc}") return False ``` ### Technical Analysis The Telegram bot token is embedded directly in the request URL. Exceptions raised by `requests` or its underlying networking libraries may include the requested URL, including its path. For this endpoint, that path contains the complete bot token. The exception is converted to a string and printed without sanitization. Consequently, DNS failures, connection failures, proxy errors, TLS errors, redirects, or other request failures may cause the credential-bearing URL to be written to terminal output, container logs, scheduler logs, or OpenClaw execution logs. Using a token in the URL is required by Telegram's Bot API, but logging the raw exception is not required for the Skill's functionality. ### Attack Path 1. The operator configures a valid `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID`. 2. An attacker or environmental fault causes the Telegram request to fail, such as by manipulating DNS, proxy configuration, firewall rules, or network availability. 3. The networking library generates an exception containing the requested URL. 4. The Skill prints the unsanitized exception a ...[truncated 678 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Dependencies Are Mutable and Installed Without Integrity Verification

Content
View full analysis
=2.31,<3 python-dotenv>=1.0,<2 ``` The documented installation command in `SKILL.md:113-117` resolves these mutable ranges directly: ```bash cd sentinel-litellm-local-router/sentinel-modality-router-skill pip install -r requirements.txt cp .env.example .env # edit .env with your ROUTER_BASE_URL, model aliases, image path, etc. ``` ### Technical Analysis The dependency constraints permit any future `requests` 2.x and `python-dotenv` 1.x release. No lockfile or package hashes authenticate the artifacts selected during installation. As a result, two installations performed at different times can resolve different code despite using the same audited project files. If a permitted future release or distribution artifact is compromised, the installation may execute or install unreviewed code. The absence of hashes also prevents `pip` from detecting an artifact that differs from the exact artifact reviewed by the project maintainer. No evidence was found that the currently named packages are typosquatted or malicious. The issue is the non-reproducible and unauthenticated dependency-resolution policy. ### Attack Path 1. A dependency account, release pipeline, package artifact, or configured Python package index is compromised. 2. A malicious or compromised release is published within an allowed version range. 3. A user follows the documented `pip install -r requirements.txt` command. 4. `pip` resolves the compromised release because it satisfies the range. 5. Package installation or subsequent import executes affected third-party code in the user's environment. An equivalent path exists where a malicious package index or mirror serves an altered artifact and no expected hash is available to reject it. ### Impact Assessment The dependency code executes wit ...[truncated 414 chars]
Remediation
View remediation
\ --hash=sha256: python-dotenv== \ --hash=sha256: ``` The actual versions and hashes should be generated from artifacts reviewed and tested by the maintainer rather than copied from placeholders. ]]>
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (13)

YARA rule 'agent_skill_credential_exfiltration_webhook': AI agent skill credential harvesting followed by webhook or external exfiltration [agent_skills]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · skill.py (reported line 101)May include surrounding context.

python
exactly this
# reason). Constructing the values from parts avoids repeating that bug.
PROBE_NAME = "Jamie Rivera"
PROBE_PHONE = "-".join(["312", "555", "0173"])  # area code included on purpose -- see docs above
PROBE_EMAIL = "@".join(["jrivera-test", "example.com"])
REDACTED_MARKER = "{{REDACTED}}"

_GATEWAY_STARTUP_TIMEOUT = 60
_GATEWAY_POLL_INTERVAL = 2


def _config() -> dict:
    port = int(os.getenv("SENTINEL_GATEWAY_PORT", "8100"))
    router_base_url = os.getenv("ROUTER_BASE_URL")
    provider_name = os.getenv("ROUTER_PROVIDER_NAME", "local-router")
    text_alias = os.getenv("TEXT_MODEL_ALIAS", "qwen-local")
    vision_alias = os.getenv("VISION_MODEL_ALIAS", "smolvlm-local")
    image_path = os.getenv("TEST_IMAGE_PATH", "./test_image.png")
    jaeger_base_url = os.getenv("JAEGER_BASE_URL", "")
    jaeger_service = os.getenv("JAEGER_SERVICE_NAME", "router")

    if not router_base_url:
        raise RuntimeError("ROUTER_BASE_URL is not set")

    return {
        "port": port,

Tainted flow: 'token' from os.getenv (line 281, credential/environment) → requests.post (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 · skill.py (reported line 287)May include surrounding context.

python
print("[skill] TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID not set -- skipping alert.")
        return False
    try:
        resp = requests.post(
            f"https://api.telegram.org/bot{token}/sendMessage",
            json={"chat_id": chat_id, "text": message, "parse_mode": "HTML"},
            timeout=10,

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

bash
cd sentinel-litellm-local-router/sentinel-modality-router-skill
pip install -r requirements.txt
cp .env.example .env
# edit .env with your ROUTER_BASE_URL, model aliases, image path, etc.

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

bash
cd sentinel-litellm-local-router/sentinel-modality-router-skill
pip install -r requirements.txt
cp .env.example .env
# edit .env with your ROUTER_BASE_URL, model aliases, image path, etc.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill explicitly performs network access, shell/subprocess actions, reads environment-derived configuration, and restarts a local security gateway, yet it declares no explicit tool scope or permission boundaries. That omission increases the chance an orchestrator or operator will invoke a disruptive, higher-privilege skill without understanding its capabilities, leading to unintended service interruption or unreviewed outbound communications.

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

python
])

    print(f"[skill] Stopping any existing Sentinel gateway on port {cfg['port']}...")
    subprocess.run(["sentinel", "gateway", "stop"], capture_output=True, text=True)

    print(f"[skill] Starting Sentinel gateway with CUSTOM_PROVIDERS -> {cfg['router_base_url']}...")
    result = subprocess.run(

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

python
subprocess.run(["sentinel", "gateway", "stop"], capture_output=True, text=True)

    print(f"[skill] Starting Sentinel gateway with CUSTOM_PROVIDERS -> {cfg['router_base_url']}...")
    result = subprocess.run(
        [
            "sentinel", "gateway", "start",
            "--port", str(cfg["port"]),

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The skill sends execution results to an external third-party service (Telegram), and on failure paths the message includes raw backend response snippets plus trace metadata. Even though the intended probes use synthetic PII, backend responses and trace identifiers can still expose internal system details, prompts, model behavior, or other sensitive operational data outside the local environment.

Content

Scanner excerpt · skill.py (reported line 287)May include surrounding context.

python
print("[skill] TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID not set -- skipping alert.")
        return False
    try:
        resp = requests.post(
            f"https://api.telegram.org/bot{token}/sendMessage",
            json={"chat_id": chat_id, "text": message, "parse_mode": "HTML"},
            timeout=10,

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

Using https://api.telegram.org/ is an intentional external network transmission to a third-party platform. In this skill's context, that increases data exposure risk because diagnostic results and observability metadata leave the local test environment and are stored or processed by Telegram infrastructure.

Content

Scanner excerpt · skill.py (reported line 288)May include surrounding context.

python
return False
    try:
        resp = requests.post(
            f"https://api.telegram.org/bot{token}/sendMessage",
            json={"chat_id": chat_id, "text": message, "parse_mode": "HTML"},
            timeout=10,
        )

Vague Triggers

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

Because this is a markdown file, vague trigger guidance applies. The phrase 'on a schedule or on demand' describes when the skill may be run but does not specify concrete invocation conditions or exclusions, which could make activation expectations unclear in systems that infer triggers from documentation.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
89% confidence
Finding

The dependency is only range-pinned (requests>=2.31,<3), so the actual installed version may vary by environment and could resolve to a release affected by one or more known advisories. In a security-sensitive skill that handles routing, tracing, and potentially PII-bearing requests, leaving the exact version unverifiable weakens supply-chain assurance and may expose the runtime to already-known flaws depending on resolver behavior.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding

python-dotenv is specified as a version range rather than an exact vetted release, so installations are not reproducible and may pull a vulnerable version if the allowed range includes one. Because this skill may load environment configuration for model routing or tracing, a vulnerable dotenv package could affect secrets handling or filesystem safety in some deployment contexts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code sends a message to the Telegram Bot API containing pass/fail results and, on failure, snippets of backend-generated content. Although the module docstring mentions that the result is sent via Telegram, there is no user confirmation or warning immediately associated with the outbound transmission of potentially sensitive diagnostic content.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.