Back to skill

Security audit

TVFetch

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real market-data skill, but it handles TradingView session tokens and runs automatic startup checks in ways users should review carefully before installing.

Install only if you are comfortable with a skill that can use and locally store a TradingView browser token, run a startup hook, contact TradingView and fallback data providers, and write cache/config files under your home directory. Prefer anonymous mode or environment variables over saving tokens, avoid passing tokens in shell commands, and review/disable the startup hook if you do not want automatic credential checks or network probes.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
scripts/lib/auth_mgr.py:49
Finding

TradingView authentication tokens are stored and accepted through insecure channels

Content
View full analysis

Vulnerability Details

File Location: scripts/lib/auth_mgr.py:49-65, scripts/lib/auth_mgr.py:132-133
Vulnerability Type: Plaintext credential storage and command-line secret exposure
Risk Level: High

Vulnerable Code

python
def cmd_set(token: str) -> int:
    """Save token to ~/.tvfetch/.env"""
    # Validate first
    valid, reason = validate_token(token)
    if not valid:
        print(f"WARNING: Token validation issue: {reason}")
        print("Saving anyway — token may still work if TV accepts it.")

    # Ensure directory exists
    DEFAULT_TVFETCH_DIR.mkdir(parents=True, exist_ok=True)

    # Read existing env file, update or add TV_AUTH_TOKEN
    existing = _load_env_file(DEFAULT_ENV_PATH)
    existing["TV_AUTH_TOKEN"] = token

    lines = [f"{k}={v}" for k, v in existing.items()]
    DEFAULT_ENV_PATH.write_text("\n".join(lines) + "\n", encoding="utf-8")

    print(f"Token saved to {DEFAULT_ENV_PATH}")
    print(f"Token preview: {token[:30]}...")
    print(f"Validation: {reason}")
    return 0
python
set_p = sub.add_parser("set", help="Save token")
set_p.add_argument("token", help="JWT token string")

Technical Analysis

The token manager writes the TradingView JWT to ~/.tvfetch/.env without explicitly enforcing restrictive permissions on either the directory or file. Path.mkdir() and Path.write_text() rely on the process umask, so the resulting credential file may be readable by other local users in permissively configured environments.

The token is also accepted as a positional command-line argument. Command-line secrets can be exposed through:

  • Shell history files
  • Process inspection tools while the command is running
  • Agent execution logs and terminal transcripts
  • Monitoring, telemetry, or audit systems that record process arguments

The command also prints the first 30 characters of the token. Although this is not the complete ...[truncated 1070 chars]

Remediation
View remediation

Remediation Suggestions

  1. Prefer system keyring storage rather than plaintext files.
  2. Accept tokens through hidden interactive input using getpass.getpass() or standard input, not process arguments.
  3. Create ~/.tvfetch with mode 0700.
  4. Create the credential file atomically with mode 0600, using flags that reject symlink traversal and prevent overwriting unexpected files.
  5. Verify ownership and permissions before reading an existing credential file.
  6. Remove or substantially shorten token previews; display only a fixed masked suffix if identification is necessary.
  7. Update documentation to warn users not to place tokens directly in shell commands.
  8. Provide token deletion and rotation instructions.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
hooks/hooks.json:3
Finding

Session-start hook performs unsolicited credential discovery, filesystem modification, and network probing

Content
View full analysis

Vulnerability Details

File Location: hooks/hooks.json:3-8, hooks/scripts/check-config.sh:40-63, scripts/lib/config.py:78-95
Vulnerability Type: Excessive automatic access beyond least privilege
Risk Level: Medium

Vulnerable Code

json
{
  "hooks": [
    {
      "event": "SessionStart",
      "command": "bash ${CLAUDE_SKILL_DIR}/hooks/scripts/check-config.sh",
      "description": "Validate tvfetch configuration on session start",
      "timeout": 10
    }
  ]
}
bash
# 4. Auth token status
$PYTHON "$SKILL_DIR/scripts/lib/config.py" --check-auth-quiet 2>/dev/null

# 5. Cache directory writability
$PYTHON -c "
from pathlib import Path
p = Path.home() / '.tvfetch'
p.mkdir(exist_ok=True)
(p / '.write_test').touch()
(p / '.write_test').unlink()
" 2>/dev/null
if [[ $? -ne 0 ]]; then
    echo "TVFETCH WARNING: Cannot write to ~/.tvfetch/ — cache may be disabled"
fi

# 6. Network connectivity (quick, non-blocking)
$PYTHON -c "
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
try:
    s.connect(('data.tradingview.com', 443))
    s.close()
except:
    print('TVFETCH WARNING: Cannot reach data.tradingview.com — offline mode only')
" 2>/dev/null

The invoked credential resolver includes:

python
# 3. ~/.tvfetch/.env
home_env = _load_env_file(DEFAULT_ENV_PATH)
if home_env.get("TV_AUTH_TOKEN"):
    return home_env["TV_AUTH_TOKEN"], ".env"

# 4. Keyring (optional)
try:
    import keyring
    kr_token = keyring.get_password("tvfetch", "auth_token")
    if kr_token:
        return kr_token, "keyring"
except (ImportError, Exception):
    pass

# 5. .env in current working directory
cwd_env = _load_env_file(Path.cwd() / ".env")
if cwd_env.get("TV_AUTH_TOKEN"):
    return cwd_env["TV_AUTH_TOKEN"], "cwd_env"

Technical Analysis

The hook runs on every agent session start, ra ...[truncated 2147 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the automatic SessionStart hook.
  2. Run configuration and connectivity checks only after the user explicitly invokes tvfetch.
  3. Separate secret-presence checks from secret retrieval; do not fetch a keyring value merely to display configuration status.
  4. Stop inspecting the current working directory's generic .env by default.
  5. Restrict configuration lookup to a dedicated tvfetch configuration file or namespaced keyring entry.
  6. Do not create directories or perform write tests until caching is actually requested.
  7. Request consent before performing connectivity tests unrelated to an active fetch.
  8. If a startup hook must remain, limit it to static checks that do not access secrets, write files, or open network connections.

other

Warning
Location
tvfetch/historical.py:139
Finding

Automatic fallback discloses requested market symbols to additional third-party providers

Content
View full analysis

Vulnerability Details

File Location: tvfetch/historical.py:139-147, tvfetch/fallback.py:78-105, tvfetch/fallback.py:141-148; conflicting disclosure at SKILL.md:440-445
Vulnerability Type: Undisclosed third-party data transmission
Risk Level: Medium

Vulnerable Code

The primary fetch path automatically invokes fallback providers:

python
except (TvSymbolNotFoundError, TvNoDataError) as primary_error:
    # Attempt fallback sources (Yahoo Finance, CCXT)
    try:
        from tvfetch.fallback import fetch_with_fallback
        return fetch_with_fallback(symbol, timeframe, bars,
                                   primary_result=None, primary_error=primary_error)
    except Exception as fallback_exc:
        log.debug("Fallback also failed: %s", fallback_exc)
        raise primary_error

Yahoo Finance fallback:

python
def fetch_yahoo(
    symbol: str,
    timeframe: str = "1D",
    bars: int = 5000,
) -> FetchResult | None:
    """Try Yahoo Finance. Returns None if yfinance not installed or symbol not found."""
    try:
        import yfinance as yf
    except ImportError:
        log.debug("yfinance not installed, skipping Yahoo fallback")
        return None

    yahoo_sym = _tv_symbol_to_yahoo(symbol)
    if not yahoo_sym:
        return None

    interval = _TV_TO_YAHOO_TF.get(timeframe)
    if not interval:
        return None

    try:
        ticker = yf.Ticker(yahoo_sym)
        df = ticker.history(period="max", interval=interval)

Cryptocurrency exchange fallback:

python
try:
    exchange = getattr(ccxt, exchange_id)()
    since = None
    ohlcv = exchange.fetch_ohlcv(ccxt_sym, ccxt_tf, since=since, limit=bars)
    if not ohlcv:
        return None

The documented security claim states:

markdown
**What this skill does NOT do:**
- Does NOT send any user data to third parties

Technical Analy

...[truncated 1826 chars]

Remediation
View remediation

Remediation Suggestions

  1. Make third-party fallback disabled by default or require explicit opt-in.
  2. Ask for user consent before contacting Yahoo Finance or a cryptocurrency exchange.
  3. Clearly enumerate every potential network provider in the Skill's security documentation.
  4. Correct the claim that no user data is sent to third parties.
  5. Add a provider allowlist so users can select acceptable fallback services.
  6. Return a structured error when TradingView fails and let the user decide whether to continue.
  7. Add automated tests proving that authentication tokens and unrelated configuration values are never passed to fallback libraries.
  8. Report the provider actually used in all output paths.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (82)

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The documentation recommends persisting a TradingView auth token using a helper command, which encourages storage of a live credential without emphasizing secure handling constraints. If an agent session, shell history, logs, or local tooling captures that command argument, the token could be exposed and reused for unauthorized access to the user's TradingView account/session.

Content

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

Method B: Save to config file (persistent)

python scripts/lib/auth_mgr.py set "eyJhbGciOiJSUzI1NiIs..."

Method C: .env file (manual)

mkdir -p ~/.tvfetch echo 'TV_AUTH_TOKEN=eyJhbGciOiJSUzI1NiIs...' > ~/.tvfetch/.env

text

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

The README tells users to write the TradingView auth token directly into ~/.tvfetch/.env, creating persistent plaintext credential storage. Plaintext .env files are commonly exposed through backups, lax filesystem permissions, accidental inclusion in bug reports, or source-control mistakes, making credential theft significantly easier.

Content

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

Method C: .env file (manual)

mkdir -p ~/.tvfetch echo 'TV_AUTH_TOKEN=eyJhbGciOiJSUzI1NiIs...' > ~/.tvfetch/.env

text

### Step 3: Verify

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented primarily as a no-key market-data fetcher, but it also includes explicit authentication-token management workflows, token testing, and storage in ~/.tvfetch/.env. That expands the skill's security scope into credential handling without clearly surfacing that risk in the top-level description, which can mislead users and reviewers about the sensitivity of the actions performed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented primarily as a no-key market-data fetcher, but it also includes explicit authentication-token management workflows, token testing, and storage in ~/.tvfetch/.env. That expands the skill's security scope into credential handling without clearly surfacing that risk in the top-level description, which can mislead users and reviewers about the sensitivity of the actions performed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill is presented primarily as a no-key market-data fetcher, but it also includes explicit authentication-token management workflows, token testing, and storage in ~/.tvfetch/.env. That expands the skill's security scope into credential handling without clearly surfacing that risk in the top-level description, which can mislead users and reviewers about the sensitivity of the actions performed.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented primarily as a no-key market-data fetcher, but it also includes explicit authentication-token management workflows, token testing, and storage in ~/.tvfetch/.env. That expands the skill's security scope into credential handling without clearly surfacing that risk in the top-level description, which can mislead users and reviewers about the sensitivity of the actions performed.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding

The skill uses 'network' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
77% confidence
Finding

The usage text documents support for saving a token to ~/.tvfetch/.env, indicating intentional credential collection and persistence. On its own this is not proof of malicious behavior, but in context it confirms the skill handles sensitive authentication material despite being marketed as 'no API key required,' which increases the attack surface and user surprise.

Content

Scanner excerpt · scripts/lib/auth_mgr.py (reported line 7)May include surrounding context.

python
Usage:
  python auth_mgr.py show           Show current token status
  python auth_mgr.py set TOKEN      Save token to ~/.tvfetch/.env
  python auth_mgr.py test           Validate token (JWT check, no network)
  python auth_mgr.py instructions   How to get your token
"""

Credential Access

High
Category
Privilege Escalation
Confidence
80% confidence
Finding

The function docstring and implementation confirm the script saves a token into a .env file, which is a sensitive secret-handling operation. Although local secret storage can be valid, it becomes risky when combined with browser token extraction instructions and absent controls like explicit permission hardening or safer secret storage mechanisms.

Content

Scanner excerpt · scripts/lib/auth_mgr.py (reported line 49)May include surrounding context.

python
def cmd_set(token: str) -> int:
    """Save token to ~/.tvfetch/.env"""
    # Validate first
    valid, reason = validate_token(token)
    if not valid:

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

These instructions tell the user to retrieve a live TradingView auth token from browser internals, including cookies and WebSocket messages. That is a credential-access pattern, not ordinary market-data functionality, and it may encourage users to extract and reuse session secrets in ways that violate least privilege and potentially platform terms.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding

The skill uses 'env' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Content

No source excerpt is available for this finding.

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

md
Resolution order for TV_AUTH_TOKEN (highest to lowest):
  1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

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

python
Resolution order for TV_AUTH_TOKEN (highest to lowest):
  1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

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

python
Resolution order for TV_AUTH_TOKEN (highest to lowest):
  1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

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

python
Resolution order for TV_AUTH_TOKEN (highest to lowest):
  1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

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

python
Resolution order for TV_AUTH_TOKEN (highest to lowest):
  1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

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

python
Resolution order for TV_AUTH_TOKEN (highest to lowest):
  1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · pyproject.toml (reported line 39)May include surrounding context.

toml
1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · pyproject.toml (reported line 40)May include surrounding context.

toml
1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/lib/config.py (reported line 8)May include surrounding context.

python
1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

python
1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/lib/config.py (reported line 85)May include surrounding context.

python
1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/lib/config.py (reported line 86)May include surrounding context.

python
1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/lib/config.py (reported line 88)May include surrounding context.

python
1. --token CLI flag
  2. TV_AUTH_TOKEN environment variable
  3. ~/.tvfetch/.env file
  4. keyring (if installed): keyring.get_password("tvfetch", "auth_token")
  5. .env in current working directory
  6. Anonymous fallback: "unauthorized_user_token"

Static analysis

No suspicious patterns detected.