Back to skill

Security audit

Nepse Analyst

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to provide NEPSE stock analysis, but its installer handles Telegram credentials unsafely and can send watchlist or alert information to Telegram.

Review this skill before installing. Use a virtual environment with pinned dependencies instead of the provided pip command, do not run setup with elevated privileges, and do not paste a Telegram bot token into the installer unless you are comfortable with it being displayed. If enabling Telegram alerts, use a narrowly scoped bot token, store it in a dedicated secret mechanism rather than ~/.bashrc, and assume watchlist symbols, prices, and alert thresholds may be sent to Telegram.

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)

T08 · Insecure Dependencies

Warning
Location
setup.sh:15
Finding

Unpinned dependencies are installed into the host Python environment

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
setup.sh:38
Finding

Telegram bot credentials are entered visibly and printed in plaintext

Content
View full analysis
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
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (26)

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 · scripts/nepse_fetch.py (reported line 34)May include surrounding context.

python
��──────────────────────────────────────────────────────────────
SKILL_DIR = Path(__file__).parent.parent
DATA_DIR = SKILL_DIR / "data"
DATA_DIR.mkdir(exist_ok=True)

WATCHLIST_FILE = DATA_DIR / "watchlist.json"
ALERTS_FILE    = DATA_DIR / "alerts.json"

TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
TELEGRAM_CHAT_ID   = os.environ.get("TELEGRAM_CHAT_ID", "")

HEADERS = {
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36"
}

# ── helpers ─────────────────────────────────────────────────────────────────

def load_json(path: Path, default):
    if path.exists():
        try:
            return json.loads(path.read_text())
        except Exception:
            return default

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 · scripts/rsi_alert.py (reported line 37)May include surrounding context.

python
��──────────────────────────────────────────────────────────────
SKILL_DIR = Path(__file__).parent.parent
DATA_DIR = SKILL_DIR / "data"
DATA_DIR.mkdir(exist_ok=True)

WATCHLIST_FILE = DATA_DIR / "watchlist.json"
ALERTS_FILE    = DATA_DIR / "alerts.json"

TELEGRAM_BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
TELEGRAM_CHAT_ID   = os.environ.get("TELEGRAM_CHAT_ID", "")

HEADERS = {
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36"
}

# ── helpers ─────────────────────────────────────────────────────────────────

def load_json(path: Path, default):
    if path.exists():
        try:
            return json.loads(path.read_text())
        except Exception:
            return default

Tainted flow: 'url' from os.environ.get (line 58, 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 · scripts/nepse_fetch.py (reported line 59)May include surrounding context.

python
return False
    try:
        url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
        resp = requests.post(url, json={
            "chat_id": TELEGRAM_CHAT_ID,
            "text": message,
            "parse_mode": "Markdown"

Tainted flow: 'url' from os.environ.get (line 58, credential/environment) → requests.get (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 · scripts/nepse_fetch.py (reported line 344)May include surrounding context.

python
symbol = symbol.upper()
    url = f"https://merolagani.com/CompanyDetail.aspx?symbol={symbol}"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=15)
        resp.raise_for_status()
        soup = BeautifulSoup(resp.text, "html.parser")

Tainted flow: 'url' from os.environ.get (line 58, credential/environment) → requests.get (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 · scripts/nepse_fetch.py (reported line 485)May include surrounding context.

python
symbol = symbol.upper()
    url = f"https://merolagani.com/CompanyDetail.aspx?symbol={symbol}"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=15)
        resp.raise_for_status()
        soup = BeautifulSoup(resp.text, "html.parser")

Tainted flow: 'url' from os.environ.get (line 58, credential/environment) → requests.get (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 · scripts/nepse_fetch.py (reported line 739)May include surrounding context.

python
symbol = symbol.upper()
    url = f"https://merolagani.com/CompanyDetail.aspx?symbol={symbol}"
    try:
        resp = requests.get(url, headers=HEADERS, timeout=15)
        resp.raise_for_status()
        soup = BeautifulSoup(resp.text, "html.parser")

Tainted flow: 'TELEGRAM_BOT_TOKEN' from os.environ.get (line 37, 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 · scripts/rsi_alert.py (reported line 68)May include surrounding context.

python
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
        return False
    try:
        r = requests.post(
            f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage",
            json={"chat_id": TELEGRAM_CHAT_ID, "text": msg, "parse_mode": "Markdown"},
            timeout=10

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill documentation instructs runtime dependency installation and Telegram configuration, which are materially different from passive stock analysis. This broadens the effective attack surface to package management, secret collection, and outbound messaging without transparent declaration, increasing the risk of unsafe execution in a financial-assistant context.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill documentation instructs runtime dependency installation and Telegram configuration, which are materially different from passive stock analysis. This broadens the effective attack surface to package management, secret collection, and outbound messaging without transparent declaration, increasing the risk of unsafe execution in a financial-assistant context.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill invokes a local Python script, performs dependency installation, manages watchlists/alerts, and documents outbound alerting, yet it declares no explicit tool scope or permissions. This creates an over-privileged, opaque execution model where shell, filesystem, environment, and network access may be used without user-visible restriction or review.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest says to use the skill for 'anything related to Nepal stock market' and includes generic phrases like 'analyze X' and 'price of X'. In a markdown/manifest context, these triggers are broad enough to cause unintended invocation because they lack clear scope boundaries or negative examples.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Automatic Telegram alert sending is an outbound-notification capability beyond simple local analysis/watchlist functionality, and it is introduced without clear security boundaries. Such messaging can transmit user interests, portfolio/watchlist symbols, or derived trading signals to a third-party service, creating privacy and exfiltration risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The cron instructions describe automatic Telegram alerts without warning that user-related data will be transmitted externally. Lack of disclosure around outbound notifications can lead to silent data sharing, especially risky in a finance skill where watchlists and alert thresholds may reflect sensitive investment intent.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill reads Telegram bot credentials from the environment and can transmit watchlist and alert information to an external messaging service. In an agent-skill context, this expands data access and outbound communication beyond core local analysis, creating privacy and policy risk if users are not clearly informed or if the skill is enabled in broader environments with sensitive configuration present.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code performs external message delivery to Telegram in addition to data retrieval and analysis. While alerts are related to market monitoring, agent skills that send data off-platform are more dangerous because they introduce an exfiltration channel and behavior that may not be expected during routine analysis requests.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The hardcoded Telegram endpoint indicates the skill is designed to send data to an external third-party service. That is not inherently malicious, but it increases risk in this context because a stock-analysis skill now has built-in off-platform communications using environment-provided credentials.

Content

Scanner excerpt · scripts/nepse_fetch.py (reported line 58)May include surrounding context.

python
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
        return False
    try:
        url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
        resp = requests.post(url, json={
            "chat_id": TELEGRAM_CHAT_ID,
            "text": message,

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This is a real external transmission to Telegram containing message text and chat metadata. In isolation it is normal API use, but in a skill environment it matters because it creates an outbound channel that can leak user-derived market interests or future modifications could piggyback on the same path.

Content

Scanner excerpt · scripts/nepse_fetch.py (reported line 59)May include surrounding context.

python
return False
    try:
        url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
        resp = requests.post(url, json={
            "chat_id": TELEGRAM_CHAT_ID,
            "text": message,
            "parse_mode": "Markdown"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The cron-check workflow sends watchlist contents and triggered alert information to Telegram without any user-facing warning, consent flow, or transparency at send time. Even if the data seems low sensitivity, portfolio interests and monitoring rules can reveal trading intent and should not be silently forwarded to third parties.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file is named rsi_alert.py, yet the module docstring explicitly documents 'Intraday Seller Detection' with triggers based on price dropping from open and volume exceeding a 10-day average. The implemented logic in check_intraday() matches seller-detection criteria and does not calculate or use RSI, so the documentation/intent signaled by the file identity diverges from the actual behavior.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest describes a NEPSE analyst skill for stock analysis, prices, signals, alerts, screening, and portfolio tracking, but does not state any need to access environment-held bot credentials or integrate with an external messaging platform. This code reads TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID and uses them to send messages to Telegram, which is an additional notification capability beyond the stated analyst role.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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 · scripts/rsi_alert.py (reported line 68)May include surrounding context.

python
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
        return False
    try:
        r = requests.post(
            f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage",
            json={"chat_id": TELEGRAM_CHAT_ID, "text": msg, "parse_mode": "Markdown"},
            timeout=10

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 · scripts/rsi_alert.py (reported line 69)May include surrounding context.

python
return False
    try:
        r = requests.post(
            f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage",
            json={"chat_id": TELEGRAM_CHAT_ID, "text": msg, "parse_mode": "Markdown"},
            timeout=10
        )

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% 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 · setup.sh (reported line 22)May include surrounding context.

sh
pip3 install requests beautifulsoup4 numpy --break-system-packages --quiet
echo "  ✓ Python deps installed"

# 2. create skill directory in openclaw workspace
echo "[2/4] Creating skill directory at ${TARGET_DIR}..."
mkdir -p "${TARGET_DIR}/scripts"
mkdir -p "${TARGET_DIR}/data"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script prompts for a Telegram bot token and chat ID, then echoes both secrets back to the terminal and recommends storing them in shell startup files. This increases the chance of accidental exposure through terminal logs, screen sharing, shell history-adjacent workflows, backups, or overly broad file permissions, especially because bot tokens are authenticators rather than mere identifiers.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
91% confidence
Finding

The setup instructions explicitly advise persisting TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID in ~/.bashrc, causing credentials to be loaded into every future shell session. Persisting secrets in a general-purpose startup file broadens exposure to local users, backup systems, dotfile syncing, accidental disclosure, and subprocess environment leakage.

Content

Scanner excerpt · setup.sh (reported line 59)May include surrounding context.

sh
echo '    }'
    echo '  }'
    echo ""
    echo "  Or export them in your shell: add to ~/.bashrc:"
    echo "  export TELEGRAM_BOT_TOKEN=\"${BOT_TOKEN}\""
    echo "  export TELEGRAM_CHAT_ID=\"${CHAT_ID}\""
fi

Static analysis

No suspicious patterns detected.